"Added file download functionality, modified media service, and updated AI chat page and state with file download feature."

This commit is contained in:
OkaykOrhmn 2024-10-03 09:35:26 +03:30
parent 0512e22727
commit f42171401e
4 changed files with 151 additions and 61 deletions

View File

@ -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,

View File

@ -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(

View File

@ -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))

View File

@ -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();
},
),
)
]),
)
], ],
); );
} }