"Added file download functionality, modified media service, and updated AI chat page and state with file download feature."
This commit is contained in:
parent
0512e22727
commit
f42171401e
|
|
@ -1,4 +1,7 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:didvan/constants/assets.dart';
|
import 'package:didvan/constants/assets.dart';
|
||||||
|
import 'package:didvan/models/ai/files_model.dart';
|
||||||
import 'package:didvan/models/requests/studio.dart';
|
import 'package:didvan/models/requests/studio.dart';
|
||||||
import 'package:didvan/models/studio_details_data.dart';
|
import 'package:didvan/models/studio_details_data.dart';
|
||||||
import 'package:didvan/models/view/action_sheet_data.dart';
|
import 'package:didvan/models/view/action_sheet_data.dart';
|
||||||
|
|
@ -11,7 +14,12 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:just_audio/just_audio.dart';
|
import 'package:just_audio/just_audio.dart';
|
||||||
|
import 'package:mime/mime.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:universal_html/html.dart' as html;
|
||||||
|
|
||||||
class MediaService {
|
class MediaService {
|
||||||
static final audioPlayer = AudioPlayer();
|
static final audioPlayer = AudioPlayer();
|
||||||
|
|
@ -141,6 +149,42 @@ class MediaService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<String?> downloadFile(String url) async {
|
||||||
|
final basename = p.basename(url).split('?accessToken=').first;
|
||||||
|
Directory? dir;
|
||||||
|
try {
|
||||||
|
if (Platform.isIOS) {
|
||||||
|
dir = await getApplicationDocumentsDirectory(); // for iOS
|
||||||
|
} else {
|
||||||
|
dir = Directory('/storage/emulated/0/Download/'); // for android
|
||||||
|
if (!await dir.exists()) dir = (await getExternalStorageDirectory())!;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
print("Cannot get download folder path $err");
|
||||||
|
}
|
||||||
|
String path = "${dir?.path}$basename";
|
||||||
|
|
||||||
|
File file = File(path);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final http.Response audioResponse = await http.get(Uri.parse(url));
|
||||||
|
final bytes = audioResponse.bodyBytes;
|
||||||
|
file.writeAsBytes(bytes);
|
||||||
|
} catch (e) {
|
||||||
|
print("Exception$e");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String downloadFileFromWeb(String url) {
|
||||||
|
html.AnchorElement anchorElement = html.AnchorElement(href: url);
|
||||||
|
anchorElement.download = url;
|
||||||
|
anchorElement.click();
|
||||||
|
return anchorElement.pathname!;
|
||||||
|
}
|
||||||
|
|
||||||
static onLoadingPickFile(BuildContext context) {
|
static onLoadingPickFile(BuildContext context) {
|
||||||
ActionSheetUtils(context).openDialog(
|
ActionSheetUtils(context).openDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@ import 'package:didvan/models/enums.dart';
|
||||||
import 'package:didvan/models/view/action_sheet_data.dart';
|
import 'package:didvan/models/view/action_sheet_data.dart';
|
||||||
import 'package:didvan/models/view/alert_data.dart';
|
import 'package:didvan/models/view/alert_data.dart';
|
||||||
import 'package:didvan/routes/routes.dart';
|
import 'package:didvan/routes/routes.dart';
|
||||||
|
import 'package:didvan/services/media/media.dart';
|
||||||
|
import 'package:didvan/services/network/request.dart';
|
||||||
|
import 'package:didvan/services/network/request_helper.dart';
|
||||||
import 'package:didvan/utils/action_sheet.dart';
|
import 'package:didvan/utils/action_sheet.dart';
|
||||||
import 'package:didvan/utils/date_time.dart';
|
import 'package:didvan/utils/date_time.dart';
|
||||||
import 'package:didvan/views/ai/ai_chat_state.dart';
|
import 'package:didvan/views/ai/ai_chat_state.dart';
|
||||||
|
|
@ -27,6 +30,7 @@ import 'package:didvan/views/widgets/didvan/icon_button.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
import 'package:didvan/views/widgets/marquee_text.dart';
|
import 'package:didvan/views/widgets/marquee_text.dart';
|
||||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
|
|
@ -313,13 +317,14 @@ class _AiChatPageState extends State<AiChatPage> {
|
||||||
bottomSheet: Column(
|
bottomSheet: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Platform.isIOS
|
// Platform.isIOS
|
||||||
? AiMessageBarIOS(
|
// ? AiMessageBarIOS(
|
||||||
bot: widget.args.bot,
|
// bot: widget.args.bot,
|
||||||
)
|
// )
|
||||||
: AiMessageBar(
|
// :
|
||||||
bot: widget.args.bot,
|
AiMessageBar(
|
||||||
),
|
bot: widget.args.bot,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
|
|
@ -590,6 +595,39 @@ class _AiChatPageState extends State<AiChatPage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (message.file != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () async {
|
||||||
|
final url =
|
||||||
|
'${RequestHelper.baseUrl + message.file.toString()}?accessToken=${RequestService.token}';
|
||||||
|
final download = kIsWeb
|
||||||
|
? MediaService
|
||||||
|
.downloadFileFromWeb(url)
|
||||||
|
: await MediaService.downloadFile(
|
||||||
|
url);
|
||||||
|
AlertData alertData = AlertData(
|
||||||
|
message: 'دانلود موفقیت آمیز بود',
|
||||||
|
aLertType: ALertType.success);
|
||||||
|
if (download == null) {
|
||||||
|
alertData = AlertData(
|
||||||
|
message:
|
||||||
|
'دانلود موفقیت آمیز نبود',
|
||||||
|
aLertType: ALertType.error);
|
||||||
|
}
|
||||||
|
ActionSheetUtils(context)
|
||||||
|
.showAlert(alertData);
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
DidvanIcons.download_solid,
|
||||||
|
size: 18,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.focusedBorder,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
if (message.error != null && message.error!)
|
if (message.error != null && message.error!)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
|
@ -613,33 +651,41 @@ class _AiChatPageState extends State<AiChatPage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
if (state.messages[mIndex].prompts[index]
|
||||||
padding: const EdgeInsets.all(8.0),
|
.text !=
|
||||||
child: InkWell(
|
null ||
|
||||||
onTap: () async {
|
(state.messages[mIndex].prompts[index]
|
||||||
await Clipboard.setData(ClipboardData(
|
.text !=
|
||||||
text: state.messages[mIndex]
|
null &&
|
||||||
.prompts[index].text
|
state.messages[mIndex].prompts[index]
|
||||||
.toString()));
|
.text!.isNotEmpty))
|
||||||
Future.delayed(
|
Padding(
|
||||||
Duration.zero,
|
padding: const EdgeInsets.all(8.0),
|
||||||
() => ActionSheetUtils(context)
|
child: InkWell(
|
||||||
.showAlert(AlertData(
|
onTap: () async {
|
||||||
message:
|
await Clipboard.setData(ClipboardData(
|
||||||
"متن با موفقیت کپی شد",
|
text: state.messages[mIndex]
|
||||||
aLertType:
|
.prompts[index].text
|
||||||
ALertType.success)),
|
.toString()));
|
||||||
);
|
Future.delayed(
|
||||||
},
|
Duration.zero,
|
||||||
child: Icon(
|
() => ActionSheetUtils(context)
|
||||||
DidvanIcons.copy_regular,
|
.showAlert(AlertData(
|
||||||
size: 18,
|
message:
|
||||||
color: Theme.of(context)
|
"متن با موفقیت کپی شد",
|
||||||
.colorScheme
|
aLertType:
|
||||||
.focusedBorder,
|
ALertType.success)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
DidvanIcons.copy_regular,
|
||||||
|
size: 18,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.focusedBorder,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ class AiChatState extends CoreProvier {
|
||||||
messages.last.prompts.add(Prompts(
|
messages.last.prompts.add(Prompts(
|
||||||
finished: false,
|
finished: false,
|
||||||
error: false,
|
error: false,
|
||||||
text: '...',
|
text: '',
|
||||||
role: 'bot',
|
role: 'bot',
|
||||||
createdAt: DateTime.now()
|
createdAt: DateTime.now()
|
||||||
.subtract(const Duration(minutes: 210))
|
.subtract(const Duration(minutes: 210))
|
||||||
|
|
|
||||||
|
|
@ -281,12 +281,6 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.focused
|
.focused
|
||||||
.withOpacity(0.5)),
|
.withOpacity(0.5)),
|
||||||
child: Center(
|
|
||||||
child: SpinKitThreeBounce(
|
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
size: 32,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
@ -310,6 +304,7 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
||||||
|
|
||||||
Row recorderAndTextMessageHandler(BuildContext context, AiChatState state) {
|
Row recorderAndTextMessageHandler(BuildContext context, AiChatState state) {
|
||||||
return Row(
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: _mRecorder!.isPaused
|
children: _mRecorder!.isPaused
|
||||||
? [
|
? [
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|
@ -412,28 +407,33 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
attachmentLayout(state, context),
|
Padding(
|
||||||
if (widget.bot.attachmentType!.isNotEmpty)
|
padding: const EdgeInsets.only(bottom: 8.0),
|
||||||
Padding(
|
child: Row(children: [
|
||||||
padding: const EdgeInsets.fromLTRB(12, 0, 12, 0),
|
attachmentLayout(state, context),
|
||||||
child: MessageBarBtn(
|
if (widget.bot.attachmentType!.isNotEmpty)
|
||||||
enable: false,
|
Padding(
|
||||||
icon: openAttach || state.file != null
|
padding: const EdgeInsets.fromLTRB(12, 0, 12, 0),
|
||||||
? DidvanIcons.close_regular
|
child: MessageBarBtn(
|
||||||
: Icons.attach_file_outlined,
|
enable: false,
|
||||||
click: () {
|
icon: openAttach || state.file != null
|
||||||
if (_mPlayer!.isPlaying) {
|
? DidvanIcons.close_regular
|
||||||
stopPlayer();
|
: Icons.attach_file_outlined,
|
||||||
}
|
click: () {
|
||||||
if (state.file != null) {
|
if (_mPlayer!.isPlaying) {
|
||||||
state.file = null;
|
stopPlayer();
|
||||||
} else {
|
}
|
||||||
openAttach = !openAttach;
|
if (state.file != null) {
|
||||||
}
|
state.file = null;
|
||||||
state.update();
|
} else {
|
||||||
},
|
openAttach = !openAttach;
|
||||||
),
|
}
|
||||||
)
|
state.update();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue