From 9531a112d4833ce81c560ad2a213eab6dc8820c2 Mon Sep 17 00:00:00 2001 From: OkaykOrhmn Date: Thu, 26 Sep 2024 12:10:01 +0330 Subject: [PATCH 1/2] idk --- lib/services/ai/ai_api_service.dart | 2 +- lib/services/app_initalizer.dart | 19 ------------------- lib/services/notification/firebase_api.dart | 7 ------- lib/views/ai/widgets/ai_message_bar.dart | 2 +- 4 files changed, 2 insertions(+), 28 deletions(-) diff --git a/lib/services/ai/ai_api_service.dart b/lib/services/ai/ai_api_service.dart index 28dc5ac..1fd3999 100644 --- a/lib/services/ai/ai_api_service.dart +++ b/lib/services/ai/ai_api_service.dart @@ -72,7 +72,7 @@ class AiApiService { mimeType = file.isAudio() ? file.isRecorded - ? 'audio/${kIsWeb && AppInitializer.getOperatingSystem() == 'iOS' ? 'webm' : 'm4a'}' + ? 'audio/m4a}' : 'audio/${file.extname.replaceAll('.', '')}' : file.isImage() ? 'image/png' diff --git a/lib/services/app_initalizer.dart b/lib/services/app_initalizer.dart index ca1a80b..5ee22c8 100644 --- a/lib/services/app_initalizer.dart +++ b/lib/services/app_initalizer.dart @@ -16,7 +16,6 @@ import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; -import 'dart:html' as html; class AppInitializer { static String? fcmToken; @@ -42,24 +41,6 @@ class AppInitializer { }); } - static String getOperatingSystem() { - final userAgent = html.window.navigator.userAgent.toLowerCase(); - - if (userAgent.contains('windows')) { - return 'Windows'; - } else if (userAgent.contains('mac os')) { - return 'MacOS'; - } else if (userAgent.contains('iphone') || userAgent.contains('ipad')) { - return 'iOS'; - } else if (userAgent.contains('android')) { - return 'Android'; - } else if (userAgent.contains('linux')) { - return 'Linux'; - } else { - return 'Unknown'; - } - } - static Future initilizeSettings() async { try { final brightness = await StorageService.getValue(key: 'brightness'); diff --git a/lib/services/notification/firebase_api.dart b/lib/services/notification/firebase_api.dart index 7bee444..3759cf0 100644 --- a/lib/services/notification/firebase_api.dart +++ b/lib/services/notification/firebase_api.dart @@ -75,13 +75,6 @@ class FirebaseApi { if (kDebugMode) { print("forground: ${NotificationData.fromJson(message.data).toJson()}"); } - const platform = MethodChannel('com.didvan.didvanapp/notification'); - - await platform.invokeMethod('showNotification', { - 'title': message.notification!.title, - 'message': message.notification!.body - }); - // } try { await NotificationService.showFirebaseNotification(message); diff --git a/lib/views/ai/widgets/ai_message_bar.dart b/lib/views/ai/widgets/ai_message_bar.dart index 5ed6476..7d0ad4e 100644 --- a/lib/views/ai/widgets/ai_message_bar.dart +++ b/lib/views/ai/widgets/ai_message_bar.dart @@ -348,7 +348,7 @@ class _AiMessageBarState extends State { state.file = FilesModel( path.toString(), name: - '${DateTime.now().millisecondsSinceEpoch ~/ 1000}.${kIsWeb && AppInitializer.getOperatingSystem() == 'iOS' ? 'webm' : 'm4a'}', + '${DateTime.now().millisecondsSinceEpoch ~/ 1000}.m4a', isRecorded: true, audio: true, image: false, From 6dad9ad68b306bf4ddd3a9d7883640f3c523a7cc Mon Sep 17 00:00:00 2001 From: kiainsta23 Date: Fri, 27 Sep 2024 15:35:01 +0330 Subject: [PATCH 2/2] friday coffegit config --- lib/models/ai/chats_model.dart | 7 +- lib/models/ai/file_type.dart | 5 + lib/models/ai/files_model.dart | 78 +++++----- lib/services/ai/ai_api_service.dart | 94 ++++++------ lib/services/app_initalizer.dart | 32 +++++ lib/services/notification/firebase_api.dart | 1 - lib/views/ai/ai_chat_page.dart | 56 ++++---- lib/views/ai/ai_chat_state.dart | 10 +- lib/views/ai/widgets/ai_message_bar.dart | 151 ++++++++------------ lib/views/profile/profile.dart | 2 +- pubspec.yaml | 2 +- 11 files changed, 234 insertions(+), 204 deletions(-) create mode 100644 lib/models/ai/file_type.dart diff --git a/lib/models/ai/chats_model.dart b/lib/models/ai/chats_model.dart index e9a08d8..793b472 100644 --- a/lib/models/ai/chats_model.dart +++ b/lib/models/ai/chats_model.dart @@ -1,5 +1,5 @@ import 'package:didvan/models/ai/bots_model.dart'; -import 'package:didvan/models/ai/files_model.dart'; +import 'package:image_picker/image_picker.dart'; class ChatsModel { int? id; @@ -98,7 +98,6 @@ class Prompts { bool? finished; bool? error; bool? audio; - FilesModel? fileLocal; int? duration; Prompts( @@ -111,7 +110,6 @@ class Prompts { this.createdAt, this.finished, this.error, - this.fileLocal, this.audio, this.duration}); @@ -147,7 +145,7 @@ class Prompts { String? text, String? file, String? fileName, - FilesModel? fileLocal, + XFile? fileLocal, String? role, String? createdAt, bool? finished, @@ -161,7 +159,6 @@ class Prompts { text: text ?? this.text, file: file ?? this.file, fileName: fileName ?? this.fileName, - fileLocal: fileLocal ?? this.fileLocal, role: role ?? this.role, createdAt: createdAt ?? this.createdAt, finished: finished ?? this.finished, diff --git a/lib/models/ai/file_type.dart b/lib/models/ai/file_type.dart new file mode 100644 index 0000000..322e6c7 --- /dev/null +++ b/lib/models/ai/file_type.dart @@ -0,0 +1,5 @@ +enum MyFileType{ + image, + audio, + file +} \ No newline at end of file diff --git a/lib/models/ai/files_model.dart b/lib/models/ai/files_model.dart index a6781cb..2d6399f 100644 --- a/lib/models/ai/files_model.dart +++ b/lib/models/ai/files_model.dart @@ -1,45 +1,45 @@ -import 'dart:io'; -import 'dart:typed_data'; +// import 'dart:io'; +// import 'dart:typed_data'; -import 'package:mime/mime.dart'; -import 'package:path/path.dart' as p; +// import 'package:mime/mime.dart'; +// import 'package:path/path.dart' as p; -class FilesModel { - final String path; - late String basename; - late String extname; - late File main; - final bool isRecorded; - final bool? audio; - final bool? image; - final bool? network; - final Uint8List? bytes; - final Duration? duration; +// class FilesModel { +// final String path; +// late String basename; +// late String extname; +// late File main; +// final bool isRecorded; +// final bool? audio; +// final bool? image; +// final bool? network; +// final Uint8List? bytes; +// final Duration? duration; - FilesModel( - this.path, { - final String? name, - this.isRecorded = false, - this.audio, - this.image, - this.network, - this.bytes, - this.duration, - }) { - basename = name ?? p.basename(path); - extname = p.extension(path); - main = File(path); - } +// FilesModel( +// this.path, { +// final String? name, +// this.isRecorded = false, +// this.audio, +// this.image, +// this.network, +// this.bytes, +// this.duration, +// }) { +// basename = name ?? p.basename(path); +// extname = path.isNotEmpty ? p.extension(path): name !=null ? p.extension(name): ''; +// main = File(path); +// } - bool isAudio() { - return audio ?? lookupMimeType(path)?.startsWith('audio/') ?? false; - } +// bool isAudio() { +// return audio ?? lookupMimeType(path)?.startsWith('audio/') ?? false; +// } - bool isImage() { - return image ?? lookupMimeType(path)?.startsWith('image/') ?? false; - } +// bool isImage() { +// return image ?? lookupMimeType(path)?.startsWith('image/') ?? false; +// } - bool isNetwork() { - return network ?? path.startsWith('blob:') || path.startsWith('/uploads'); - } -} +// bool isNetwork() { +// return network ?? path.startsWith('blob:') || path.startsWith('/uploads'); +// } +// } diff --git a/lib/services/ai/ai_api_service.dart b/lib/services/ai/ai_api_service.dart index 1fd3999..d56ced2 100644 --- a/lib/services/ai/ai_api_service.dart +++ b/lib/services/ai/ai_api_service.dart @@ -2,13 +2,12 @@ import 'dart:async'; import 'dart:convert'; - -import 'package:didvan/models/ai/files_model.dart'; -import 'package:didvan/services/app_initalizer.dart'; import 'package:didvan/services/storage/storage.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:http_parser/http_parser.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:mime/mime.dart'; class AiApiService { static const String baseUrl = 'https://api.didvan.app/ai'; @@ -17,7 +16,7 @@ class AiApiService { {required final String url, required final String message, final int? chatId, - final FilesModel? file, + final XFile? file, final bool? edite}) async { final headers = { "Authorization": "Bearer ${await StorageService.getValue(key: 'token')}", @@ -36,47 +35,61 @@ class AiApiService { } if (file != null) { - if (file.duration != null) { - request.fields['duration'] = file.duration!.inSeconds.toString(); - } + // if (file.duration != null) { + // request.fields['duration'] = file.duration!.inSeconds.toString(); + // } Uint8List bytes; String filename; String mimeType; - if (kIsWeb) { - // For web platform - if (file.bytes != null) { - bytes = file.bytes!; - } else { - final Uri audioUri = Uri.parse(file.path.replaceAll('%3A', ':')); - final http.Response audioResponse = await http.get(audioUri); - bytes = audioResponse.bodyBytes; - // final f = File.fromUri(Uri.parse(file.path)); - // bytes = await f.readAsBytes(); - // Fetch the blob using JavaScript interop - // final blob = await html.window - // .fetch(file.path.replaceAll('%3A', ':')) - // .then((response) => response.blob()); + bytes = await file.readAsBytes(); + filename = file.name; + mimeType = lookupMimeType(filename) ?? 'application/octet-stream'; + print("mimeType: $mimeType"); - // // Read the blob as an array buffer - // final reader = html.FileReader(); - // reader.readAsArrayBuffer(blob); - // await reader.onLoadEnd.first; - // bytes = reader.result as Uint8List; - } - } else { - // For other platforms - bytes = await file.main.readAsBytes(); - } - filename = file.basename; - - mimeType = file.isAudio() - ? file.isRecorded - ? 'audio/m4a}' - : 'audio/${file.extname.replaceAll('.', '')}' - : file.isImage() - ? 'image/png' - : 'application/pdf'; +// switch (file.extname) { +// case '.mp3': +// mimeType = 'audio/mpeg'; +// break; +// case '.wav': +// mimeType = 'audio/wav'; +// break; +// case '.aac': +// mimeType = 'audio/aac'; +// break; +// case '.m4a': +// mimeType = 'audio/x-m4a'; // or 'audio/aac' +// break; +// case '.ogg': +// mimeType = 'audio/ogg'; +// break; +// case '.flac': +// mimeType = 'audio/x-flac'; +// break; +// case '.wma': +// mimeType = 'audio/x-ms-wma'; +// break; +// case '.amr': +// mimeType = 'audio/amr'; +// break; +// case '.midi': +// mimeType = 'audio/midi'; +// break; +// case '.weba': +// mimeType = 'audio/webm'; +// break; +// case '.png': +// mimeType = 'image/png'; +// break; +// case '.jpg': +// mimeType = 'image/jpeg'; +// break; +// case '.pdf': +// mimeType = 'application/pdf'; +// break; +// default: +// mimeType = lookupMimeType(filename) ?? 'application/octet-stream'; +// } request.files.add(http.MultipartFile.fromBytes( 'file', @@ -86,7 +99,6 @@ class AiApiService { )); } - // print("req: ${request.files}"); // print("req: ${request.fields}"); return request; diff --git a/lib/services/app_initalizer.dart b/lib/services/app_initalizer.dart index 5ee22c8..49286a9 100644 --- a/lib/services/app_initalizer.dart +++ b/lib/services/app_initalizer.dart @@ -1,6 +1,7 @@ // ignore_for_file: avoid_web_libraries_in_flutter import 'package:didvan/main.dart'; +import 'package:didvan/models/ai/file_type.dart'; import 'package:didvan/models/notification_message.dart'; import 'package:didvan/models/requests/news.dart'; import 'package:didvan/models/requests/radar.dart'; @@ -16,6 +17,7 @@ import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; +import 'package:path/path.dart' as p; class AppInitializer { static String? fcmToken; @@ -204,4 +206,34 @@ class AppInitializer { Navigator.of(context).pushNamed(Routes.web, arguments: src); } } + + static MyFileType getFileType(String extName) { + MyFileType result; + + switch (p.extension(extName)) { + case '.mp3': + case '.wav': + case '.aac': + case '.m4a': + case '.ogg': + case '.flac': + case '.wma': + case '.amr': + case '.midi': + case '.weba': + result = MyFileType.audio; + break; + case '.png': + case '.jpg': + result = MyFileType.image; + break; + case '.pdf': + result = MyFileType.file; + break; + default: + result = MyFileType.file; + } + + return result; + } } diff --git a/lib/services/notification/firebase_api.dart b/lib/services/notification/firebase_api.dart index 3759cf0..33f7907 100644 --- a/lib/services/notification/firebase_api.dart +++ b/lib/services/notification/firebase_api.dart @@ -6,7 +6,6 @@ import 'package:didvan/services/notification/notification_service.dart'; import 'package:didvan/services/storage/storage.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'package:get/get.dart'; class FirebaseApi { diff --git a/lib/views/ai/ai_chat_page.dart b/lib/views/ai/ai_chat_page.dart index e30a419..db9e227 100644 --- a/lib/views/ai/ai_chat_page.dart +++ b/lib/views/ai/ai_chat_page.dart @@ -1,5 +1,7 @@ // ignore_for_file: library_private_types_in_public_api, deprecated_member_use, depend_on_referenced_packages +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; @@ -7,10 +9,11 @@ import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/constants/assets.dart'; import 'package:didvan/models/ai/ai_chat_args.dart'; import 'package:didvan/models/ai/chats_model.dart'; -import 'package:didvan/models/ai/files_model.dart'; +import 'package:didvan/models/ai/file_type.dart'; import 'package:didvan/models/enums.dart'; import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/models/view/alert_data.dart'; +import 'package:didvan/services/app_initalizer.dart'; import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/date_time.dart'; import 'package:didvan/views/ai/ai_chat_state.dart'; @@ -26,6 +29,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:persian_number_utility/persian_number_utility.dart'; import 'package:provider/provider.dart'; @@ -268,10 +272,12 @@ class _AiChatPageState extends State { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), padding: EdgeInsets.only( - bottom: state.file != null && - !state.file!.isRecorded + bottom: + state.file != null && + !state.isRecorded ? 150 - : 100), + : + 100), itemBuilder: (context, mIndex) { final prompts = state.messages[mIndex].prompts; final time = state.messages[mIndex].dateTime; @@ -329,13 +335,12 @@ class _AiChatPageState extends State { Widget messageBubble(Prompts message, BuildContext context, AiChatState state, int index, int mIndex) { - FilesModel? file = message.fileLocal ?? - (message.file == null - ? null - : FilesModel(message.file.toString(), - duration: message.duration != null - ? Duration(seconds: message.duration!) - : null)); + String? fileUrl = message.file; + String? fileName = message.fileName; + MyFileType? fileType ; + if(fileName != null){ + fileType = AppInitializer.getFileType(fileName); + } MarkdownStyleSheet defaultMarkdownStyleSheet = MarkdownStyleSheet( pPadding: const EdgeInsets.all(0.8), @@ -431,22 +436,22 @@ class _AiChatPageState extends State { : Column( children: [ if (message.role.toString().contains('user') && - file != null) - (file.isAudio() + fileUrl != null && fileName != null) + (fileType == MyFileType.audio // && (!kIsWeb && !Platform.isIOS) ) ? Padding( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8), child: AudioWave( - file: file.path, - totalDuration: file.duration, + file: fileUrl, + // totalDuration: file.duration, ), ) - : file.isImage() + : fileType == MyFileType.image ? Padding( padding: const EdgeInsets.all(8.0), - child: messageImage(file), + child: messageImage(fileUrl), ) : Padding( padding: const EdgeInsets.all( @@ -509,6 +514,7 @@ class _AiChatPageState extends State { .remove(message); state.messages.last.prompts.add( message.copyWith(error: false)); + state.file = state.messages.last.prompts.last.file!= null? XFile(state.messages.last.prompts.last.file!): null; state.update(); await state .postMessage(widget.args.bot); @@ -626,7 +632,7 @@ class _AiChatPageState extends State { ), if (state.file != null && !kIsWeb) FutureBuilder( - future: state.file!.main.length(), + future: state.file!.length(), builder: (context, snapshot) { if (!snapshot.hasData) { return const SizedBox(); @@ -644,23 +650,23 @@ class _AiChatPageState extends State { ); } - Widget messageImage(FilesModel file) { + Widget messageImage(String file) { return GestureDetector( onTap: () => ActionSheetUtils(context) - .openInteractiveViewer(context, file.path, !file.isNetwork()), - child: file.isNetwork() - ? file.path.startsWith('blob:') + .openInteractiveViewer(context, file, !(file.startsWith('blob:') || file.startsWith('/uploads'))), + child: (file.startsWith('blob:') || file.startsWith('/uploads')) + ? file.startsWith('blob:') ? ClipRRect( borderRadius: DesignConfig.lowBorderRadius, - child: Image.network(file.path)) + child: Image.network(file)) : SkeletonImage( pWidth: MediaQuery.sizeOf(context).width / 1, pHeight: MediaQuery.sizeOf(context).height / 6, - imageUrl: file.path, + imageUrl: file, ) : ClipRRect( borderRadius: DesignConfig.lowBorderRadius, - child: Image.file(file.main)), + child: Image.file(File(file))), ); } } diff --git a/lib/views/ai/ai_chat_state.dart b/lib/views/ai/ai_chat_state.dart index a87041d..355de20 100644 --- a/lib/views/ai/ai_chat_state.dart +++ b/lib/views/ai/ai_chat_state.dart @@ -6,11 +6,11 @@ import 'package:didvan/main.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:persian_number_utility/persian_number_utility.dart'; import 'package:provider/provider.dart'; import 'package:didvan/models/ai/bots_model.dart'; import 'package:didvan/models/ai/chats_model.dart'; -import 'package:didvan/models/ai/files_model.dart'; import 'package:didvan/models/ai/messages_model.dart'; import 'package:didvan/models/enums.dart'; import 'package:didvan/models/view/alert_data.dart'; @@ -33,7 +33,8 @@ class AiChatState extends CoreProvier { final ScrollController scrollController = ScrollController(); int? chatId; ChatsModel? chat; - FilesModel? file; + XFile? file; + bool isRecorded = false; TextEditingController message = TextEditingController(); Future _scrolledEnd() async { @@ -159,6 +160,10 @@ class AiChatState extends CoreProvier { chatId: chatId, file: file, edite: isEdite); + file = null; + isRecorded = false; + update(); + final res = await AiApiService().getResponse(req).catchError((e) { _onError(e); // return e; @@ -166,7 +171,6 @@ class AiChatState extends CoreProvier { String responseMessgae = ''; String dataMessgae = ''; - file = null; update(); final r = res.listen((value) async { diff --git a/lib/views/ai/widgets/ai_message_bar.dart b/lib/views/ai/widgets/ai_message_bar.dart index 7d0ad4e..a2b46b8 100644 --- a/lib/views/ai/widgets/ai_message_bar.dart +++ b/lib/views/ai/widgets/ai_message_bar.dart @@ -6,11 +6,10 @@ import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/models/ai/bots_model.dart'; import 'package:didvan/models/ai/chats_model.dart'; -import 'package:didvan/models/ai/files_model.dart'; +import 'package:didvan/models/ai/file_type.dart'; import 'package:didvan/models/ai/messages_model.dart'; import 'package:didvan/services/app_initalizer.dart'; import 'package:didvan/services/media/media.dart'; -import 'package:didvan/services/media/voice.dart'; import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/date_time.dart'; import 'package:didvan/views/ai/ai_chat_state.dart'; @@ -33,6 +32,7 @@ import 'package:persian_number_utility/persian_number_utility.dart'; import 'package:provider/provider.dart'; import 'package:record/record.dart'; +import 'package:http/http.dart' as http; import 'package:path/path.dart' as p; class AiMessageBar extends StatefulWidget { @@ -126,8 +126,8 @@ class _AiMessageBarState extends State { ignoring: state.onResponsing, child: Container( padding: const EdgeInsets.symmetric(vertical: 24).copyWith( - top: openAttach || - (state.file != null && !state.file!.isRecorded) + top: openAttach + ||(state.file != null && !state.isRecorded) ? 0 : 24), decoration: BoxDecoration( @@ -162,25 +162,7 @@ class _AiMessageBarState extends State { FilePickerResult? result = await MediaService.pickPdfFile(); if (result != null) { - if (kIsWeb) { - Uint8List? bytes = result.files.first - .bytes; // Access the bytes property - String? name = result.files.first.name; - - // Store bytes and file name directly in your state or model - state.file = FilesModel( - '', // No need for a file path on web - name: name, - bytes: bytes, - audio: false, - image: false, - ); - } else { - state.file = FilesModel( - result.files.single.path!, - audio: false, - image: false); - } + state.file = result.files.first.xFile; openAttach = false; } @@ -234,13 +216,8 @@ class _AiMessageBarState extends State { return; } - state.file = kIsWeb - ? FilesModel(pickedFile.path, - name: pickedFile.name, - image: true, - audio: false) - : FilesModel(file!.path, - image: true, audio: false); + state.file = + kIsWeb ? pickedFile : XFile(file!.path); openAttach = false; await Future.delayed( Duration.zero, @@ -261,24 +238,8 @@ class _AiMessageBarState extends State { FilePickerResult? result = await MediaService.pickAudioFile(); if (result != null) { - if (kIsWeb) { - Uint8List? bytes = result.files.first - .bytes; // Access the bytes property - String? name = result.files.first.name; + state.file = result.files.first.xFile; - state.file = FilesModel( - '', // No need for a file path on web - name: name, - bytes: bytes, - audio: true, - image: false, - ); - } else { - state.file = FilesModel( - result.files.single.path!, - audio: true, - image: false); - } openAttach = false; } await Future.delayed( @@ -339,21 +300,29 @@ class _AiMessageBarState extends State { path = await record .stop(); - Duration? duration = - await VoiceService - .getDuration( - src: path ?? - ''); + // Duration? duration = + // await VoiceService + // .getDuration( + // src: path ?? + // ''); - state.file = FilesModel( - path.toString(), - name: - '${DateTime.now().millisecondsSinceEpoch ~/ 1000}.m4a', - isRecorded: true, - audio: true, - image: false, - duration: - duration); + final Uri audioUri = + Uri.parse(path! + .replaceAll( + '%3A', + ':')); + final http.Response + audioResponse = + await http.get( + audioUri); + final bytes = + audioResponse + .bodyBytes; + state.file = kIsWeb + ? XFile.fromData( + bytes) + : XFile(path!); + state.isRecorded = true; _timer.cancel(); _countTimer.value = 0; state.update(); @@ -409,9 +378,11 @@ class _AiMessageBarState extends State { ) : MessageBarBtn( enable: (state.file != - null && - state.file! - .isRecorded) || + null + && + state + .isRecorded + ) || (widget.bot .attachment == 1) || @@ -421,10 +392,11 @@ class _AiMessageBarState extends State { .send_light, click: () async { if ((state.file == - null || + null + || !state - .file! - .isRecorded) && + .isRecorded + ) && (widget.bot .attachment != 1) && @@ -459,10 +431,7 @@ class _AiMessageBarState extends State { ?.path, fileName: state .file - ?.basename, - fileLocal: - state - .file, + ?.name, finished: true, role: 'user', @@ -490,14 +459,12 @@ class _AiMessageBarState extends State { .text, finished: true, - file: state - .file - ?.path, - fileName: state - .file - ?.basename, - fileLocal: - state.file, + file: state + .file + ?.path, + fileName: state + .file + ?.name, role: 'user', createdAt: DateTime.now() @@ -585,9 +552,10 @@ class _AiMessageBarState extends State { ], ), ) - : state.file != null && - state.file! - .isRecorded + : state.file != null + && + AppInitializer.getFileType(state.file!.name) + == MyFileType.audio && state.isRecorded ? audioContainer() : Form( child: @@ -803,9 +771,16 @@ class _AiMessageBarState extends State { } AnimatedVisibility fileContainer() { + late MyFileType fileType; final state = context.watch(); + if(state.file != null ){ + fileType = AppInitializer.getFileType(state.file!.name); + } + return AnimatedVisibility( - isVisible: state.file != null && !state.file!.isRecorded, + isVisible: state.file != null + && !state.isRecorded + , duration: DesignConfig.lowAnimationDuration, child: Container( decoration: BoxDecoration( @@ -816,19 +791,19 @@ class _AiMessageBarState extends State { margin: const EdgeInsets.only(bottom: 8, left: 12, right: 12), child: Row( children: [ - state.file != null && state.file!.isImage() + state.file != null && (fileType == MyFileType.image) ? SizedBox( width: 32, height: 42, child: ClipRRect( borderRadius: DesignConfig.lowBorderRadius, - child: state.file!.isNetwork() + child: state.file!.path.startsWith('blob:') ? Image.network( state.file!.path, fit: BoxFit.cover, ) : Image.file( - state.file!.main, + File(state.file!.path), fit: BoxFit.cover, ))) : const Icon(Icons.file_copy), @@ -842,14 +817,14 @@ class _AiMessageBarState extends State { SizedBox( height: 24, child: MarqueeText( - text: state.file != null ? state.file!.basename : '', + text: state.file != null ? state.file!.name : '', style: const TextStyle(fontSize: 14), stop: const Duration(seconds: 3), ), ), if (state.file != null && !kIsWeb) FutureBuilder( - future: state.file!.main.length(), + future: state.file!.length(), builder: (context, snapshot) { if (!snapshot.hasData) { return const SizedBox(); diff --git a/lib/views/profile/profile.dart b/lib/views/profile/profile.dart index 58a24e5..3932a46 100644 --- a/lib/views/profile/profile.dart +++ b/lib/views/profile/profile.dart @@ -348,7 +348,7 @@ class _ProfilePageState extends State { ), const SizedBox(height: 16), DidvanText( - 'نسخه نرم‌افزار: 3.3.3', + 'نسخه نرم‌افزار: 3.3.4', style: Theme.of(context).textTheme.bodySmall, ), ], diff --git a/pubspec.yaml b/pubspec.yaml index 6ca54d9..8386ce2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.3.3+3330 +version: 3.3.4+3340 environment: sdk: ">=2.19.0 <3.0.0"