From 01566ce45d0d20919c6a5b916bb04b2495257de2 Mon Sep 17 00:00:00 2001 From: Seyed Amir Hossein Mosavi Date: Wed, 11 Sep 2024 11:59:44 +0330 Subject: [PATCH] "Added error handling and loading indicators to media and AI API services, updated media service to handle file picking and loading, and modified audio wave and AI message bar widgets to handle audio playback and file attachments." --- ios/Podfile | 2 +- ios/Podfile.lock | 226 +++++++++++------------ ios/Runner.xcodeproj/project.pbxproj | 14 +- ios/Runner/Info.plist | 121 ++++++------ lib/services/ai/ai_api_service.dart | 8 +- lib/services/media/media.dart | 66 +++++-- lib/utils/action_sheet.dart | 5 +- lib/views/ai/widgets/ai_message_bar.dart | 30 ++- lib/views/ai/widgets/audio_wave.dart | 25 ++- 9 files changed, 282 insertions(+), 215 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index 2d17462..1b99167 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '12.0' +platform :ios, '14.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4903c89..6ac8ca0 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,59 +1,67 @@ PODS: - - assets_audio_player (0.0.1): - - Flutter - - assets_audio_player_web (0.0.1): + - audio_session (0.0.1): - Flutter - awesome_notifications (0.8.1): - Flutter - IosAwnCore (~> 0.8.0) - - awesome_notifications_core (0.0.1): + - DKImagePickerController/Core (4.3.9): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.9) + - DKImagePickerController/PhotoGallery (4.3.9): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.9) + - DKPhotoGallery (0.0.19): + - DKPhotoGallery/Core (= 0.0.19) + - DKPhotoGallery/Model (= 0.0.19) + - DKPhotoGallery/Preview (= 0.0.19) + - DKPhotoGallery/Resource (= 0.0.19) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.19): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.19): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery - Flutter - - better_player (0.0.1): - - Cache (~> 6.0.0) + - Firebase/CoreOnly (10.29.0): + - FirebaseCore (= 10.29.0) + - Firebase/Messaging (10.29.0): + - Firebase/CoreOnly + - FirebaseMessaging (~> 10.29.0) + - firebase_core (3.3.0): + - Firebase/CoreOnly (= 10.29.0) - Flutter - - GCDWebServer - - HLSCachingReverseProxyServer - - PINCache - - Cache (6.0.0) - - Firebase/Auth (10.25.0): - - Firebase/CoreOnly - - FirebaseAuth (~> 10.25.0) - - Firebase/CoreOnly (10.25.0): - - FirebaseCore (= 10.25.0) - - Firebase/Messaging (10.25.0): - - Firebase/CoreOnly - - FirebaseMessaging (~> 10.25.0) - - firebase_auth (4.19.6): - - Firebase/Auth (= 10.25.0) + - firebase_messaging (15.0.4): + - Firebase/Messaging (= 10.29.0) - firebase_core - Flutter - - firebase_core (2.31.1): - - Firebase/CoreOnly (= 10.25.0) - - Flutter - - firebase_messaging (14.9.2): - - Firebase/Messaging (= 10.25.0) - - firebase_core - - Flutter - - FirebaseAppCheckInterop (10.25.0) - - FirebaseAuth (10.25.0): - - FirebaseAppCheckInterop (~> 10.17) - - FirebaseCore (~> 10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.8) - - GoogleUtilities/Environment (~> 7.8) - - GTMSessionFetcher/Core (< 4.0, >= 2.1) - - RecaptchaInterop (~> 100.0) - - FirebaseCore (10.25.0): + - FirebaseCore (10.29.0): - FirebaseCoreInternal (~> 10.0) - GoogleUtilities/Environment (~> 7.12) - GoogleUtilities/Logger (~> 7.12) - - FirebaseCoreInternal (10.25.0): + - FirebaseCoreInternal (10.29.0): - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseInstallations (10.25.0): + - FirebaseInstallations (10.29.0): - FirebaseCore (~> 10.0) - GoogleUtilities/Environment (~> 7.8) - GoogleUtilities/UserDefaults (~> 7.8) - PromisesObjC (~> 2.1) - - FirebaseMessaging (10.25.0): + - FirebaseMessaging (10.29.0): - FirebaseCore (~> 10.0) - FirebaseInstallations (~> 10.0) - GoogleDataTransport (~> 9.3) @@ -63,15 +71,10 @@ PODS: - GoogleUtilities/UserDefaults (~> 7.8) - nanopb (< 2.30911.0, >= 2.30908.0) - Flutter (1.0.0) - - flutter_local_notifications (0.0.1): - - Flutter - flutter_secure_storage (6.0.0): - Flutter - flutter_vibrate (0.0.1): - Flutter - - GCDWebServer (3.5.4): - - GCDWebServer/Core (= 3.5.4) - - GCDWebServer/Core (3.5.4) - GoogleDataTransport (9.4.1): - GoogleUtilities/Environment (~> 7.7) - nanopb (< 2.30911.0, >= 2.30908.0) @@ -101,10 +104,6 @@ PODS: - GoogleUtilities/UserDefaults (7.13.3): - GoogleUtilities/Logger - GoogleUtilities/Privacy - - GTMSessionFetcher/Core (3.4.1) - - HLSCachingReverseProxyServer (0.1.0): - - GCDWebServer (~> 3.5) - - PINCache (>= 3.0.1-beta.3) - home_widget (0.0.1): - Flutter - image_cropper (0.0.4): @@ -113,110 +112,96 @@ PODS: - image_picker_ios (0.0.1): - Flutter - IosAwnCore (0.8.0) + - just_audio (0.0.1): + - Flutter - nanopb (2.30910.0): - nanopb/decode (= 2.30910.0) - nanopb/encode (= 2.30910.0) - nanopb/decode (2.30910.0) - nanopb/encode (2.30910.0) + - package_info_plus (0.4.5): + - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - permission_handler_apple (9.3.0): - Flutter - - PINCache (3.0.4): - - PINCache/Arc-exception-safe (= 3.0.4) - - PINCache/Core (= 3.0.4) - - PINCache/Arc-exception-safe (3.0.4): - - PINCache/Core - - PINCache/Core (3.0.4): - - PINOperation (~> 1.2.3) - - PINOperation (1.2.3) - PromisesObjC (2.4.0) - - RecaptchaInterop (100.0.0) - - record (0.0.1): + - record_darwin (1.0.0): - Flutter + - FlutterMacOS - rive_common (0.0.1): - Flutter + - SDWebImage (5.19.7): + - SDWebImage/Core (= 5.19.7) + - SDWebImage/Core (5.19.7) - sqflite (0.0.3): - Flutter - FlutterMacOS + - SwiftyGif (5.4.5) - TOCropViewController (2.6.1) - - url_launcher_ios (0.0.1): + - video_player_avfoundation (0.0.1): - Flutter - - wakelock (0.0.1): + - FlutterMacOS + - wakelock_plus (0.0.1): - Flutter - webview_flutter_wkwebview (0.0.1): - Flutter DEPENDENCIES: - - assets_audio_player (from `.symlinks/plugins/assets_audio_player/ios`) - - assets_audio_player_web (from `.symlinks/plugins/assets_audio_player_web/ios`) + - audio_session (from `.symlinks/plugins/audio_session/ios`) - awesome_notifications (from `.symlinks/plugins/awesome_notifications/ios`) - - awesome_notifications_core (from `.symlinks/plugins/awesome_notifications_core/ios`) - - better_player (from `.symlinks/plugins/better_player/ios`) - - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - Flutter (from `Flutter`) - - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - flutter_vibrate (from `.symlinks/plugins/flutter_vibrate/ios`) - home_widget (from `.symlinks/plugins/home_widget/ios`) - image_cropper (from `.symlinks/plugins/image_cropper/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - just_audio (from `.symlinks/plugins/just_audio/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - - record (from `.symlinks/plugins/record/ios`) + - record_darwin (from `.symlinks/plugins/record_darwin/ios`) - rive_common (from `.symlinks/plugins/rive_common/ios`) - sqflite (from `.symlinks/plugins/sqflite/darwin`) - - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - - wakelock (from `.symlinks/plugins/wakelock/ios`) + - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) + - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) SPEC REPOS: trunk: - - Cache + - DKImagePickerController + - DKPhotoGallery - Firebase - - FirebaseAppCheckInterop - - FirebaseAuth - FirebaseCore - FirebaseCoreInternal - FirebaseInstallations - FirebaseMessaging - - GCDWebServer - GoogleDataTransport - GoogleUtilities - - GTMSessionFetcher - - HLSCachingReverseProxyServer - IosAwnCore - nanopb - - PINCache - - PINOperation - PromisesObjC - - RecaptchaInterop + - SDWebImage + - SwiftyGif - TOCropViewController EXTERNAL SOURCES: - assets_audio_player: - :path: ".symlinks/plugins/assets_audio_player/ios" - assets_audio_player_web: - :path: ".symlinks/plugins/assets_audio_player_web/ios" + audio_session: + :path: ".symlinks/plugins/audio_session/ios" awesome_notifications: :path: ".symlinks/plugins/awesome_notifications/ios" - awesome_notifications_core: - :path: ".symlinks/plugins/awesome_notifications_core/ios" - better_player: - :path: ".symlinks/plugins/better_player/ios" - firebase_auth: - :path: ".symlinks/plugins/firebase_auth/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" firebase_core: :path: ".symlinks/plugins/firebase_core/ios" firebase_messaging: :path: ".symlinks/plugins/firebase_messaging/ios" Flutter: :path: Flutter - flutter_local_notifications: - :path: ".symlinks/plugins/flutter_local_notifications/ios" flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" flutter_vibrate: @@ -227,68 +212,65 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/image_cropper/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" + just_audio: + :path: ".symlinks/plugins/just_audio/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" - record: - :path: ".symlinks/plugins/record/ios" + record_darwin: + :path: ".symlinks/plugins/record_darwin/ios" rive_common: :path: ".symlinks/plugins/rive_common/ios" sqflite: :path: ".symlinks/plugins/sqflite/darwin" - url_launcher_ios: - :path: ".symlinks/plugins/url_launcher_ios/ios" - wakelock: - :path: ".symlinks/plugins/wakelock/ios" + video_player_avfoundation: + :path: ".symlinks/plugins/video_player_avfoundation/darwin" + wakelock_plus: + :path: ".symlinks/plugins/wakelock_plus/ios" webview_flutter_wkwebview: :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" SPEC CHECKSUMS: - assets_audio_player: edee322b9cb625571b830b35872ead1a295fd917 - assets_audio_player_web: 19826380c44375761aa0b9053665c1e3fbc3b86b + audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207 awesome_notifications: db394d2e061e4583ba0f738ddea611e3986cc3fb - awesome_notifications_core: d02eed89738fa362d56cbd372850e9adcd2c6bef - better_player: 2406bfe8175203c7a46fa15f9d778d73b12e1646 - Cache: 4ca7e00363fca5455f26534e5607634c820ffc2d - Firebase: 0312a2352584f782ea56f66d91606891d4607f06 - firebase_auth: 193301a23be35329120526c6a83672ea40676472 - firebase_core: 22e117a2e0dec3cb318c8f53f2dd01c140375617 - firebase_messaging: 8999827b6efc9c3ab4b1f9dc246deaa7f13dbf88 - FirebaseAppCheckInterop: 5da5ce93e8797a215e3f677fb0654b74e736c8b8 - FirebaseAuth: c0f93dcc570c9da2bffb576969d793e95c344fbb - FirebaseCore: 7ec4d0484817f12c3373955bc87762d96842d483 - FirebaseCoreInternal: 910a81992c33715fec9263ca7381d59ab3a750b7 - FirebaseInstallations: 91950fe859846fff0fbd296180909dd273103b09 - FirebaseMessaging: 88950ba9485052891ebe26f6c43a52bb62248952 + DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c + DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 + file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 + Firebase: cec914dab6fd7b1bd8ab56ea07ce4e03dd251c2d + firebase_core: 57aeb91680e5d5e6df6b888064be7c785f146efb + firebase_messaging: c862b3d2b973ecc769194dc8de09bd22c77ae757 + FirebaseCore: 30e9c1cbe3d38f5f5e75f48bfcea87d7c358ec16 + FirebaseCoreInternal: df84dd300b561c27d5571684f389bf60b0a5c934 + FirebaseInstallations: 913cf60d0400ebd5d6b63a28b290372ab44590dd + FirebaseMessaging: 7b5d8033e183ab59eb5b852a53201559e976d366 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be flutter_vibrate: 9f4c2ab57008965f78969472367c329dd77eb801 - GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15 - GTMSessionFetcher: 8000756fc1c19d2e5697b90311f7832d2e33f6cd - HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181 home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57 image_cropper: 60c2789d1f1a78c873235d4319ca0c34a69f2d98 image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 IosAwnCore: ed1b2b6d84962a758354dbacd9ce525c72ce28a9 + just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa nanopb: 438bc412db1928dac798aa6fd75726007be04262 + package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 - PINCache: d9a87a0ff397acffe9e2f0db972ac14680441158 - PINOperation: fb563bcc9c32c26d6c78aaff967d405aa2ee74a7 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - RecaptchaInterop: 7d1a4a01a6b2cb1610a47ef3f85f0c411434cb21 - record: cae05d8dd3cdb1dea3511b20e5a5811a1ae00d0d + record_darwin: df0a677188e5fed18472550298e675f19ddaffbe rive_common: c537b4eed761e903a9403d93c347b69bd7a4762f + SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3 sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec + SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863 - url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f + video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3 + wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 webview_flutter_wkwebview: be0f0d33777f1bfd0c9fdcb594786704dbf65f36 -PODFILE CHECKSUM: d9825a12b7b9489d4776b9c9434f6b977b656841 +PODFILE CHECKSUM: 76346ded4b0438dd89826a25813fc91ef681eb1f COCOAPODS: 1.15.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index c9f31e5..f8cfa73 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -220,6 +220,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1530; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; @@ -478,7 +479,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -503,7 +504,7 @@ INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Didvan; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.news"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -565,7 +566,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -615,10 +616,11 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; @@ -641,7 +643,7 @@ INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Didvan; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.news"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -673,7 +675,7 @@ INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Didvan; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.news"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index ebc0c4f..1ba4651 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -1,62 +1,69 @@ + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + didvan + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + FirebaseAppDelegateProxyEnabled + + LSRequiresIPhoneOS + + NSCameraUsageDescription + We need to access to the user gallery to add user profile photo + NSMicrophoneUsageDescription + Some message to describe why you need this permission + NSPhotoLibraryUsageDescription + We need to access to the user gallery to add user profile photo + UIApplicationSupportsIndirectInputEvents + + UIBackgroundModes + + audio + fetch + remote-notification + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortrait + + UIViewControllerBasedStatusBarAppearance + + UNNotificationServiceExtension + + $(PRODUCT_BUNDLE_IDENTIFIER).MyNotificationServiceExtension + + NSAppleMusicUsageDescription + This app requires access to Apple Music to [explain specific reason]. + NSMicrophoneUsageDescription + ... explain why the app uses the microphone here ... + NSAppTransportSecurity - CADisableMinimumFrameDurationOnPhone - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - didvan - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - FirebaseAppDelegateProxyEnabled - - LSRequiresIPhoneOS - - NSCameraUsageDescription - We need to access to the user gallery to add user profile photo - NSMicrophoneUsageDescription - We need to access to the microphone to record audio file - NSPhotoLibraryUsageDescription - We need to access to the user gallery to add user profile photo - UIApplicationSupportsIndirectInputEvents - - UIBackgroundModes - - audio - fetch - remote-notification - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortrait - - UIViewControllerBasedStatusBarAppearance - - UNNotificationServiceExtension - - $(PRODUCT_BUNDLE_IDENTIFIER).MyNotificationServiceExtension - - NSMicrophoneUsageDescription - Some message to describe why you need this permission + NSAllowsArbitraryLoads + - \ No newline at end of file + + diff --git a/lib/services/ai/ai_api_service.dart b/lib/services/ai/ai_api_service.dart index eff2925..7f68fd2 100644 --- a/lib/services/ai/ai_api_service.dart +++ b/lib/services/ai/ai_api_service.dart @@ -35,7 +35,13 @@ class AiApiService { request.fields['edit'] = edite.toString().toLowerCase(); } if (file != null) { - final length = await file.length(); + int length = 0; + try { + length = await file.length(); + // ... + } catch (e) { + // Handle the error or return an error response + } String basename = p.basename(file.path); String? mimeType = lookupMimeType(file.path); // Use MIME type instead of file extension diff --git a/lib/services/media/media.dart b/lib/services/media/media.dart index 2f60b1b..044c20b 100644 --- a/lib/services/media/media.dart +++ b/lib/services/media/media.dart @@ -1,10 +1,16 @@ +import 'package:didvan/constants/assets.dart'; +import 'package:didvan/main.dart'; import 'package:didvan/models/requests/studio.dart'; import 'package:didvan/models/studio_details_data.dart'; +import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/providers/media.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; import 'package:didvan/services/storage/storage.dart'; +import 'package:didvan/utils/action_sheet.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:just_audio/just_audio.dart'; import 'package:file_picker/file_picker.dart'; @@ -96,24 +102,58 @@ class MediaService { } static Future pickImage({required ImageSource source}) async { - final imagePicker = ImagePicker(); - final XFile? pickedFile = await imagePicker.pickImage(source: source); - return pickedFile; + try { + final imagePicker = ImagePicker(); + final XFile? pickedFile = await imagePicker.pickImage(source: source); + return pickedFile; + } catch (e) { + e.printError(info: 'Pick Image Fail'); + return null; + } } static Future pickPdfFile() async { - final FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: ['pdf'], - allowMultiple: false, - ); - return result; + try { + final FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['pdf'], + allowMultiple: false, + onFileLoading: onLoadingPickFile, + ); + return result; + } catch (e) { + e.printError(info: 'Pick PDF Fail'); + return null; + } } static Future pickAudioFile() async { - return await FilePicker.platform.pickFiles( - type: FileType.audio, - allowMultiple: false, - ); + try { + return await FilePicker.platform.pickFiles( + type: FileType.audio, + allowMultiple: false, + onFileLoading: onLoadingPickFile, + ); + } catch (e) { + e.printError(info: 'Pick Audio Fail'); + return null; + } + } + + static onLoadingPickFile(FilePickerStatus filePickerStatus) { + ActionSheetUtils.context = navigatorKey.currentContext!; + ActionSheetUtils.openDialog( + barrierDismissible: false, + data: ActionSheetData( + content: Center( + child: Image.asset( + Assets.loadingAnimation, + width: 60, + height: 60, + ), + ), + hasConfirmButton: false, + hasDismissButton: false, + )); } } diff --git a/lib/utils/action_sheet.dart b/lib/utils/action_sheet.dart index 1412f5b..6439036 100644 --- a/lib/utils/action_sheet.dart +++ b/lib/utils/action_sheet.dart @@ -182,9 +182,12 @@ class ActionSheetUtils { ); } - static Future openDialog({required ActionSheetData data}) async { + static Future openDialog( + {required ActionSheetData data, + final bool barrierDismissible = true}) async { await showDialog( context: context, + barrierDismissible: barrierDismissible, builder: (context) => BackdropFilter( filter: ImageFilter.blur( sigmaX: data.isBackgroundDropBlur ? 10 : 0, diff --git a/lib/views/ai/widgets/ai_message_bar.dart b/lib/views/ai/widgets/ai_message_bar.dart index 67a0d0c..d0b834a 100644 --- a/lib/views/ai/widgets/ai_message_bar.dart +++ b/lib/views/ai/widgets/ai_message_bar.dart @@ -9,6 +9,7 @@ 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/services/media/media.dart'; +import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/date_time.dart'; import 'package:didvan/views/ai/ai_chat_state.dart'; import 'package:didvan/views/ai/history_ai_chat_state.dart'; @@ -159,6 +160,7 @@ class _AiMessageBarState extends State { if (result != null) { state.file = FilesModel(result.files.single.path!); + openAttach = false; // Do something with the selected PDF file } }, @@ -170,6 +172,9 @@ class _AiMessageBarState extends State { icon: CupertinoIcons.photo, color: Colors.deepOrangeAccent, click: () async { + MediaService.onLoadingPickFile( + FilePickerStatus.done); + final pickedFile = await MediaService.pickImage( source: ImageSource.gallery); @@ -187,12 +192,23 @@ class _AiMessageBarState extends State { ), compressQuality: 30, ); - if (file == null) return; + + if (file == null) { + ActionSheetUtils.pop(); + + return; + } + } + if (pickedFile == null) { + ActionSheetUtils.pop(); + + return; } - if (pickedFile == null) return; state.file = kIsWeb ? FilesModel(pickedFile.path) : FilesModel(file!.path); + openAttach = false; + ActionSheetUtils.pop(); }, ), if (historyState.bot!.attachmentType! @@ -207,6 +223,7 @@ class _AiMessageBarState extends State { if (result != null) { state.file = FilesModel(result.files.single.path!); + openAttach = false; } }, ) @@ -259,6 +276,7 @@ class _AiMessageBarState extends State { final path = await record .stop(); + state.file = FilesModel( path.toString(), isRecorded: true); @@ -285,12 +303,12 @@ class _AiMessageBarState extends State { .hasPermission()) { Directory? downloadDir = - await getDownloadsDirectory(); + await getApplicationDocumentsDirectory(); record.start( const RecordConfig(), path: - '${downloadDir!.path}/${DateTime.now().millisecondsSinceEpoch ~/ 1000}.m4a'); + '${downloadDir.path}/${DateTime.now().millisecondsSinceEpoch ~/ 1000}.m4a'); startTimer(); } }, @@ -638,10 +656,8 @@ class _AiMessageBarState extends State { return InkWell( onTap: () async { await click?.call(); + state.update(); - setState(() { - openAttach = false; - }); }, child: Column( children: [ diff --git a/lib/views/ai/widgets/audio_wave.dart b/lib/views/ai/widgets/audio_wave.dart index 6be3f11..4b0dede 100644 --- a/lib/views/ai/widgets/audio_wave.dart +++ b/lib/views/ai/widgets/audio_wave.dart @@ -12,6 +12,7 @@ import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:get/get.dart'; import 'package:just_audio/just_audio.dart'; class AudioWave extends StatefulWidget { @@ -63,6 +64,7 @@ class _AudioWaveState extends State { if (widget.file.startsWith('/uploads')) { final audioSource = LockCachingAudioSource(Uri.parse( '${RequestHelper.baseUrl + path}?accessToken=${RequestService.token}')); + await audioSource.request(); totalDuration = await audioPlayer.setAudioSource(audioSource) ?? Duration.zero; } else { @@ -86,15 +88,24 @@ class _AudioWaveState extends State { Future listeners() async { audioPlayer.positionStream.listen((position) async { - for (var i = 0; i < itemCount; i++) { - if (i < - ((position.inMilliseconds * 40) / totalDuration.inMilliseconds)) { - final ran = randomsDisable.value[i]; - randoms.value[i] = ran; - } else { - randoms.value[i] = 0; + if (randomsDisable.value.isEmpty) return; + + try { + for (var i = 0; i < itemCount; i++) { + if (i < randomsDisable.value.length && + i < + ((position.inMilliseconds * 40) / + totalDuration.inMilliseconds)) { + final ran = randomsDisable.value[i]; + randoms.value[i] = ran; + } else { + randoms.value[i] = 0; + } } + } catch (e) { + e.printError(info: 'listener Error'); } + if (position.inMilliseconds >= totalDuration.inMilliseconds) { audioPlayer.stop(); audioPlayer.seek(Duration.zero);