diff --git a/.gitignore b/.gitignore index 24476c5d..a0ba6efd 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,12 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +# Generated Files for macOS, Linux, and Windows +/linux/flutter/generated_plugin_registrant.cc +/linux/flutter/generated_plugin_registrant.h +/linux/flutter/generated_plugins.cmake +/macos/Flutter/GeneratedPluginRegistrant.swift +/windows/flutter/generated_plugin_registrant.cc +/windows/flutter/generated_plugin_registrant.h +/windows/flutter/generated_plugins.cmake diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9625e105..7c569640 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/ios/Podfile b/ios/Podfile index 88359b22..5002e643 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '11.0' +platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -37,5 +37,17 @@ end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) + + target.build_configurations.each do |config| + # You can remove unused permissions here + # for more infomation: https://github.com/BaseflowIT/flutter-permission-handler/blob/master/permission_handler/ios/Classes/PermissionHandlerEnums.h + # e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0' + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ + '$(inherited)', + + ## dart: PermissionGroup.notification + 'PERMISSION_NOTIFICATIONS=1', + ] + end end end diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f87d916b..d811272e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -628,42 +628,86 @@ PODS: - abseil/base/base_internal - abseil/base/config - abseil/meta/type_traits - - app_minimizer (0.0.1): - - Flutter - - AppAuth (1.6.1): - - AppAuth/Core (= 1.6.1) - - AppAuth/ExternalUserAgent (= 1.6.1) - - AppAuth/Core (1.6.1) - - AppAuth/ExternalUserAgent (1.6.1): + - AppAuth (1.6.2): + - AppAuth/Core (= 1.6.2) + - AppAuth/ExternalUserAgent (= 1.6.2) + - AppAuth/Core (1.6.2) + - AppAuth/ExternalUserAgent (1.6.2): - AppAuth/Core + - audio_session (0.0.1): + - Flutter + - audioplayers_darwin (0.0.1): + - Flutter - BoringSSL-GRPC (0.0.24): - BoringSSL-GRPC/Implementation (= 0.0.24) - BoringSSL-GRPC/Interface (= 0.0.24) - BoringSSL-GRPC/Implementation (0.0.24): - BoringSSL-GRPC/Interface (= 0.0.24) - BoringSSL-GRPC/Interface (0.0.24) - - cloud_firestore (4.8.2): - - Firebase/Firestore (= 10.10.0) + - cloud_firestore (4.14.0): + - Firebase/Firestore (= 10.18.0) - firebase_core - Flutter - nanopb (< 2.30910.0, >= 2.30908.0) - device_info_plus (0.0.1): - Flutter - - Firebase/CoreOnly (10.10.0): - - FirebaseCore (= 10.10.0) - - Firebase/Firestore (10.10.0): + - DKImagePickerController/Core (4.3.4): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.4) + - DKImagePickerController/PhotoGallery (4.3.4): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.4) + - DKPhotoGallery (0.0.17): + - DKPhotoGallery/Core (= 0.0.17) + - DKPhotoGallery/Model (= 0.0.17) + - DKPhotoGallery/Preview (= 0.0.17) + - DKPhotoGallery/Resource (= 0.0.17) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.17): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.17): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter + - Firebase/CoreOnly (10.18.0): + - FirebaseCore (= 10.18.0) + - Firebase/Firestore (10.18.0): - Firebase/CoreOnly - - FirebaseFirestore (~> 10.10.0) - - firebase_core (2.14.0): - - Firebase/CoreOnly (= 10.10.0) + - FirebaseFirestore (~> 10.18.0) + - firebase_core (2.24.2): + - Firebase/CoreOnly (= 10.18.0) - Flutter - - FirebaseCore (10.10.0): + - FirebaseAppCheckInterop (10.22.0) + - FirebaseCore (10.18.0): - FirebaseCoreInternal (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - GoogleUtilities/Logger (~> 7.8) - - FirebaseCoreInternal (10.11.0): + - GoogleUtilities/Environment (~> 7.12) + - GoogleUtilities/Logger (~> 7.12) + - FirebaseCoreExtension (10.22.0): + - FirebaseCore (~> 10.0) + - FirebaseCoreInternal (10.22.0): - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseFirestore (10.10.0): + - FirebaseFirestore (10.18.0): + - FirebaseCore (~> 10.0) + - FirebaseCoreExtension (~> 10.0) + - FirebaseFirestoreInternal (~> 10.17) + - FirebaseSharedSwift (~> 10.0) + - FirebaseFirestoreInternal (10.22.0): - abseil/algorithm (~> 1.20220623.0) - abseil/base (~> 1.20220623.0) - abseil/container/flat_hash_map (~> 1.20220623.0) @@ -672,25 +716,31 @@ PODS: - abseil/strings/strings (~> 1.20220623.0) - abseil/time (~> 1.20220623.0) - abseil/types (~> 1.20220623.0) + - FirebaseAppCheckInterop (~> 10.17) - FirebaseCore (~> 10.0) - - "gRPC-C++ (~> 1.50.1)" + - "gRPC-C++ (~> 1.49.1)" - leveldb-library (~> 1.22) - - nanopb (< 2.30910.0, >= 2.30908.0) + - nanopb (< 2.30911.0, >= 2.30908.0) + - FirebaseSharedSwift (10.22.0) - fl_location (0.0.1): - Flutter - Flutter (1.0.0) - flutter_fgbg (0.0.1): - Flutter - - flutter_foreground_task (0.0.1): - - Flutter - - flutter_ringtone_player (0.0.1): + - flutter_native_splash (0.0.1): - Flutter - flutter_secure_storage (6.0.0): - Flutter + - flutter_volume_controller (0.0.1): + - Flutter + - fluttertoast (0.0.2): + - Flutter + - Toast - google_sign_in_ios (0.0.1): - Flutter - - GoogleSignIn (~> 6.2) - - GoogleDataTransport (9.2.3): + - FlutterMacOS + - GoogleSignIn (~> 7.0) + - GoogleDataTransport (9.4.0): - GoogleUtilities/Environment (~> 7.7) - nanopb (< 2.30910.0, >= 2.30908.0) - PromisesObjC (< 3.0, >= 1.2) @@ -699,10 +749,10 @@ PODS: - MLKitBarcodeScanning (~> 3.0.0) - GoogleMLKit/MLKitCore (4.0.0): - MLKitCommon (~> 9.0.0) - - GoogleSignIn (6.2.4): + - GoogleSignIn (7.0.0): - AppAuth (~> 1.5) - - GTMAppAuth (~> 1.3) - - GTMSessionFetcher/Core (< 3.0, >= 1.1) + - GTMAppAuth (< 3.0, >= 1.3) + - GTMSessionFetcher/Core (< 4.0, >= 1.1) - GoogleToolboxForMac/DebugUtils (2.3.2): - GoogleToolboxForMac/Defines (= 2.3.2) - GoogleToolboxForMac/Defines (2.3.2) @@ -715,19 +765,24 @@ PODS: - GoogleToolboxForMac/Defines (= 2.3.2) - "GoogleToolboxForMac/NSString+URLArguments (= 2.3.2)" - "GoogleToolboxForMac/NSString+URLArguments (2.3.2)" - - GoogleUtilities/Environment (7.11.1): + - GoogleUtilities/Environment (7.13.0): + - GoogleUtilities/Privacy - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.11.1): + - GoogleUtilities/Logger (7.13.0): - GoogleUtilities/Environment - - "GoogleUtilities/NSData+zlib (7.11.1)" - - GoogleUtilities/UserDefaults (7.11.1): + - GoogleUtilities/Privacy + - "GoogleUtilities/NSData+zlib (7.13.0)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (7.13.0) + - GoogleUtilities/UserDefaults (7.13.0): - GoogleUtilities/Logger + - GoogleUtilities/Privacy - GoogleUtilitiesComponents (1.1.0): - GoogleUtilities/Logger - - "gRPC-C++ (1.50.1)": - - "gRPC-C++/Implementation (= 1.50.1)" - - "gRPC-C++/Interface (= 1.50.1)" - - "gRPC-C++/Implementation (1.50.1)": + - "gRPC-C++ (1.49.1)": + - "gRPC-C++/Implementation (= 1.49.1)" + - "gRPC-C++/Interface (= 1.49.1)" + - "gRPC-C++/Implementation (1.49.1)": - abseil/base/base (= 1.20220623.0) - abseil/base/core_headers (= 1.20220623.0) - abseil/cleanup/cleanup (= 1.20220623.0) @@ -752,13 +807,13 @@ PODS: - abseil/types/span (= 1.20220623.0) - abseil/types/variant (= 1.20220623.0) - abseil/utility/utility (= 1.20220623.0) - - "gRPC-C++/Interface (= 1.50.1)" - - gRPC-Core (= 1.50.1) - - "gRPC-C++/Interface (1.50.1)" - - gRPC-Core (1.50.1): - - gRPC-Core/Implementation (= 1.50.1) - - gRPC-Core/Interface (= 1.50.1) - - gRPC-Core/Implementation (1.50.1): + - "gRPC-C++/Interface (= 1.49.1)" + - gRPC-Core (= 1.49.1) + - "gRPC-C++/Interface (1.49.1)" + - gRPC-Core (1.49.1): + - gRPC-Core/Implementation (= 1.49.1) + - gRPC-Core/Interface (= 1.49.1) + - gRPC-Core/Implementation (1.49.1): - abseil/base/base (= 1.20220623.0) - abseil/base/core_headers (= 1.20220623.0) - abseil/container/flat_hash_map (= 1.20220623.0) @@ -783,15 +838,15 @@ PODS: - abseil/types/variant (= 1.20220623.0) - abseil/utility/utility (= 1.20220623.0) - BoringSSL-GRPC (= 0.0.24) - - gRPC-Core/Interface (= 1.50.1) - - gRPC-Core/Interface (1.50.1) - - GTMAppAuth (1.3.1): + - gRPC-Core/Interface (= 1.49.1) + - gRPC-Core/Interface (1.49.1) + - GTMAppAuth (2.0.0): - AppAuth/Core (~> 1.6) - - GTMSessionFetcher/Core (< 3.0, >= 1.5) + - GTMSessionFetcher/Core (< 4.0, >= 1.5) - GTMSessionFetcher/Core (2.3.0) - isar_flutter_libs (1.0.0): - Flutter - - leveldb-library (1.22.2) + - leveldb-library (1.22.4) - MLImage (1.0.0-beta4) - MLKitBarcodeScanning (3.0.0): - MLKitCommon (~> 9.0) @@ -810,51 +865,58 @@ PODS: - GTMSessionFetcher/Core (< 3.0, >= 1.1) - MLImage (= 1.0.0-beta4) - MLKitCommon (~> 9.0) - - mobile_scanner (3.2.0): + - mobile_scanner (3.5.5): - Flutter - GoogleMLKit/BarcodeScanning (~> 4.0.0) - - nanopb (2.30909.0): - - nanopb/decode (= 2.30909.0) - - nanopb/encode (= 2.30909.0) - - nanopb/decode (2.30909.0) - - nanopb/encode (2.30909.0) + - nanopb (2.30909.1): + - nanopb/decode (= 2.30909.1) + - nanopb/encode (= 2.30909.1) + - nanopb/decode (2.30909.1) + - nanopb/encode (2.30909.1) - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - pedometer (0.0.1): + - Flutter - permission_handler_apple (9.1.1): - Flutter - - PromisesObjC (2.2.0) + - PromisesObjC (2.4.0) - screen_state (0.0.1): - Flutter + - SDWebImage (5.19.0): + - SDWebImage/Core (= 5.19.0) + - SDWebImage/Core (5.19.0) - sensors_plus (0.0.1): - Flutter - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS + - SwiftyGif (5.4.4) + - Toast (4.1.0) - url_launcher_ios (0.0.1): - Flutter - vibration (1.7.5): - Flutter DEPENDENCIES: - - app_minimizer (from `.symlinks/plugins/app_minimizer/ios`) + - audio_session (from `.symlinks/plugins/audio_session/ios`) + - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`) - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - fl_location (from `.symlinks/plugins/fl_location/ios`) - Flutter (from `Flutter`) - flutter_fgbg (from `.symlinks/plugins/flutter_fgbg/ios`) - - flutter_foreground_task (from `.symlinks/plugins/flutter_foreground_task/ios`) - - flutter_ringtone_player (from `.symlinks/plugins/flutter_ringtone_player/ios`) + - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/ios`) + - flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`) + - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`) - isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`) - mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - pedometer (from `.symlinks/plugins/pedometer/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - screen_state (from `.symlinks/plugins/screen_state/ios`) - sensors_plus (from `.symlinks/plugins/sensors_plus/ios`) - - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - vibration (from `.symlinks/plugins/vibration/ios`) @@ -863,10 +925,16 @@ SPEC REPOS: - abseil - AppAuth - BoringSSL-GRPC + - DKImagePickerController + - DKPhotoGallery - Firebase + - FirebaseAppCheckInterop - FirebaseCore + - FirebaseCoreExtension - FirebaseCoreInternal - FirebaseFirestore + - FirebaseFirestoreInternal + - FirebaseSharedSwift - GoogleDataTransport - GoogleMLKit - GoogleSignIn @@ -884,14 +952,21 @@ SPEC REPOS: - MLKitVision - nanopb - PromisesObjC + - SDWebImage + - SwiftyGif + - Toast EXTERNAL SOURCES: - app_minimizer: - :path: ".symlinks/plugins/app_minimizer/ios" + audio_session: + :path: ".symlinks/plugins/audio_session/ios" + audioplayers_darwin: + :path: ".symlinks/plugins/audioplayers_darwin/ios" cloud_firestore: :path: ".symlinks/plugins/cloud_firestore/ios" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" firebase_core: :path: ".symlinks/plugins/firebase_core/ios" fl_location: @@ -900,28 +975,30 @@ EXTERNAL SOURCES: :path: Flutter flutter_fgbg: :path: ".symlinks/plugins/flutter_fgbg/ios" - flutter_foreground_task: - :path: ".symlinks/plugins/flutter_foreground_task/ios" - flutter_ringtone_player: - :path: ".symlinks/plugins/flutter_ringtone_player/ios" + flutter_native_splash: + :path: ".symlinks/plugins/flutter_native_splash/ios" flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" + flutter_volume_controller: + :path: ".symlinks/plugins/flutter_volume_controller/ios" + fluttertoast: + :path: ".symlinks/plugins/fluttertoast/ios" google_sign_in_ios: - :path: ".symlinks/plugins/google_sign_in_ios/ios" + :path: ".symlinks/plugins/google_sign_in_ios/darwin" isar_flutter_libs: :path: ".symlinks/plugins/isar_flutter_libs/ios" mobile_scanner: :path: ".symlinks/plugins/mobile_scanner/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" + pedometer: + :path: ".symlinks/plugins/pedometer/ios" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" screen_state: :path: ".symlinks/plugins/screen_state/ios" sensors_plus: :path: ".symlinks/plugins/sensors_plus/ios" - shared_preferences_foundation: - :path: ".symlinks/plugins/shared_preferences_foundation/darwin" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" vibration: @@ -929,50 +1006,62 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: abseil: 926fb7a82dc6d2b8e1f2ed7f3a718bce691d1e46 - app_minimizer: a7e8bf2b20361723f210b079a8ab00230942ff6d - AppAuth: e48b432bb4ba88b10cb2bcc50d7f3af21e78b9c2 + AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570 + audio_session: 4f3e461722055d21515cf3261b64c973c062f345 + audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40 BoringSSL-GRPC: 3175b25143e648463a56daeaaa499c6cb86dad33 - cloud_firestore: 818ebb1a8235177a0dcf7005c14aed5408b8342c - device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea - Firebase: facd334e557a979bd03a0b58d90fd56b52b8aba0 - firebase_core: 85b6664038311940ad60584eaabc73103c61f5de - FirebaseCore: d027ff503d37edb78db98429b11f580a24a7df2a - FirebaseCoreInternal: 9e46c82a14a3b3a25be4e1e151ce6d21536b89c0 - FirebaseFirestore: b3bb12a497c9d13e80ec3158dbb75ded03592e8d + cloud_firestore: 73eece22ce25a0565238c283ee9990f1618d8063 + device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 + DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac + DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 + file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de + Firebase: 414ad272f8d02dfbf12662a9d43f4bba9bec2a06 + firebase_core: 0af4a2b24f62071f9bf283691c0ee41556dcb3f5 + FirebaseAppCheckInterop: 58db3e9494751399cf3e7b7e3e705cff71099153 + FirebaseCore: 2322423314d92f946219c8791674d2f3345b598f + FirebaseCoreExtension: 6394c00b887d0bebadbc7049c464aa0cbddc5d41 + FirebaseCoreInternal: bca337352024b18424a61e478460547d46c4c753 + FirebaseFirestore: 171bcbb57a1a348dd171a0d5e382c03ef85a77bb + FirebaseFirestoreInternal: 86fe6fc8ca156309cb4842d2d7b2f15c669a64a0 + FirebaseSharedSwift: 48076404e6e52372290d15a07d2ed1d2f1754023 fl_location: 68b4a6c4aad2a453493ff66f196e0748280cf43e - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_fgbg: 31c0d1140a131daea2d342121808f6aa0dcd879d - flutter_foreground_task: 21ef182ab0a29a3005cc72cd70e5f45cb7f7f817 - flutter_ringtone_player: 15eba85187230b87b2512f0e1b92225618bc03e7 + flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be - google_sign_in_ios: 1256ff9d941db546373826966720b0c24804bcdd - GoogleDataTransport: f0308f5905a745f94fb91fea9c6cbaf3831cb1bd + flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529 + fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265 + google_sign_in_ios: 1bfaf6607b44cd1b24c4d4bc39719870440f9ce1 + GoogleDataTransport: bed3a36c04c8552479fbb9b76326e0fc69bddcb2 GoogleMLKit: 2bd0dc6253c4d4f227aad460f69215a504b2980e - GoogleSignIn: 5651ce3a61e56ca864160e79b484cd9ed3f49b7a + GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842 GoogleToolboxForMac: 8bef7c7c5cf7291c687cf5354f39f9db6399ad34 - GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749 + GoogleUtilities: d053d902a8edaa9904e1bd00c37535385b8ed152 GoogleUtilitiesComponents: 679b2c881db3b615a2777504623df6122dd20afe - "gRPC-C++": 0968bace703459fd3e5dcb0b2bed4c573dbff046 - gRPC-Core: 17108291d84332196d3c8466b48f016fc17d816d - GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd + "gRPC-C++": 2df8cba576898bdacd29f0266d5236fa0e26ba6a + gRPC-Core: a21a60aefc08c68c247b439a9ef97174b0c54f96 + GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2 isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073 - leveldb-library: f03246171cce0484482ec291f88b6d563699ee06 + leveldb-library: 06a69cc7582d64b29424a63e085e683cc188230a MLImage: 7bb7c4264164ade9bf64f679b40fb29c8f33ee9b MLKitBarcodeScanning: 04e264482c5f3810cb89ebc134ef6b61e67db505 MLKitCommon: c1b791c3e667091918d91bda4bba69a91011e390 MLKitVision: 8baa5f46ee3352614169b85250574fde38c36f49 - mobile_scanner: 47056db0c04027ea5f41a716385542da28574662 - nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 - path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8 + mobile_scanner: 202ab6f652e40a9add68b10de4c4fb2a745c4348 + nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5 + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c + pedometer: 381969883680ade42559782cc41a3bbd453d8234 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 - PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 screen_state: a7ae251997e97f3f001839df09b57313b0ddef18 + SDWebImage: 981fd7e860af070920f249fd092420006014c3eb sensors_plus: 5717760720f7e6acd96fdbd75b7428f5ad755ec2 - shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c - url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 + SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f + Toast: ec33c32b8688982cecc6348adeae667c1b9938da + url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 vibration: 7d883d141656a1c1a6d8d238616b2042a51a1241 -PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 +PODFILE CHECKSUM: b0d4019d63a06aa0d701044dbc594a28e1b1d370 -COCOAPODS: 1.12.0 +COCOAPODS: 1.15.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 75c1f8ae..1f30e52b 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -124,7 +124,6 @@ EE7366E14E5A260606CB06CD /* Pods-Runner.release.xcconfig */, B33171C6E207358295CC5A05 /* Pods-Runner.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -143,6 +142,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 66B6F9F61F03F5B8E2EEE6AC /* [CP] Embed Pods Frameworks */, + 9BDD1910BFDD1BE8CE6A1772 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -159,7 +159,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -250,6 +250,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + 9BDD1910BFDD1BE8CE6A1772 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; F7AF27F2B7862160C6BE8F5A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -347,7 +364,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -363,6 +380,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = A36HPZ86P4; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -424,7 +442,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -473,7 +491,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -491,6 +509,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = A36HPZ86P4; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -513,6 +532,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = A36HPZ86P4; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a3..5e31d3d3 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - + + PermissionGroupNotification + This app needs notification permissions to show notifications. NSCameraUsageDescription This app needs camera access to scan QR codes NSPhotoLibraryUsageDescription diff --git a/lib/app/data/models/alarm_model.dart b/lib/app/data/models/alarm_model.dart index 44e340e2..141978da 100644 --- a/lib/app/data/models/alarm_model.dart +++ b/lib/app/data/models/alarm_model.dart @@ -22,6 +22,7 @@ class AlarmModel { late bool isShakeEnabled; late bool isQrEnabled; late bool isPedometerEnabled; + late bool isPhotochallengeEnabled; late int intervalToAlarm; late bool isActivityEnabled; late String location; @@ -34,6 +35,7 @@ class AlarmModel { late int numMathsQuestions; late int mathsDifficulty; late String qrValue; + late String imageurl; List? sharedUserIds; late String ownerId; late String ownerName; @@ -83,6 +85,8 @@ class AlarmModel { required this.isPedometerEnabled, required this.numberOfSteps, required this.activityInterval, + required this.isPhotochallengeEnabled, + required this.imageurl, this.offsetDetails = const {}, required this.mainAlarmTime, required this.label, @@ -146,6 +150,8 @@ class AlarmModel { numMathsQuestions = documentSnapshot['numMathsQuestions']; isQrEnabled = documentSnapshot['isQrEnabled']; qrValue = documentSnapshot['qrValue']; + isPhotochallengeEnabled = documentSnapshot['isPhotochallengeEnabled']; + imageurl = documentSnapshot['imageurl']; isShakeEnabled = documentSnapshot['isShakeEnabled']; shakeTimes = documentSnapshot['shakeTimes']; isPedometerEnabled = documentSnapshot['isPedometerEnabled']; @@ -190,6 +196,8 @@ class AlarmModel { numMathsQuestions = alarmData['numMathsQuestions']; isQrEnabled = alarmData['isQrEnabled']; qrValue = alarmData['qrValue']; + isPhotochallengeEnabled = alarmData['isPhotochallengeEnabled']; + imageurl = alarmData['imageurl']; isShakeEnabled = alarmData['isShakeEnabled']; shakeTimes = alarmData['shakeTimes']; isPedometerEnabled = alarmData['isPedometerEnabled']; @@ -241,6 +249,8 @@ class AlarmModel { 'numMathsQuestions': alarmRecord.numMathsQuestions, 'isQrEnabled': alarmRecord.isQrEnabled, 'qrValue': alarmRecord.qrValue, + 'isPhotochallengeEnabled': alarmRecord.isPhotochallengeEnabled, + 'imageurl': alarmRecord.imageurl, 'isShakeEnabled': alarmRecord.isShakeEnabled, 'shakeTimes': alarmRecord.shakeTimes, 'isPedometerEnabled': alarmRecord.isPedometerEnabled, diff --git a/lib/app/data/models/alarm_model.g.dart b/lib/app/data/models/alarm_model.g.dart index 452defaa..c8744b39 100644 --- a/lib/app/data/models/alarm_model.g.dart +++ b/lib/app/data/models/alarm_model.g.dart @@ -52,168 +52,178 @@ const AlarmModelSchema = CollectionSchema( name: r'gradient', type: IsarType.long, ), - r'intervalToAlarm': PropertySchema( + r'imageurl': PropertySchema( id: 7, + name: r'imageurl', + type: IsarType.string, + ), + r'intervalToAlarm': PropertySchema( + id: 8, name: r'intervalToAlarm', type: IsarType.long, ), r'isActivityEnabled': PropertySchema( - id: 8, + id: 9, name: r'isActivityEnabled', type: IsarType.bool, ), r'isEnabled': PropertySchema( - id: 9, + id: 10, name: r'isEnabled', type: IsarType.bool, ), r'isLocationEnabled': PropertySchema( - id: 10, + id: 11, name: r'isLocationEnabled', type: IsarType.bool, ), r'isMathsEnabled': PropertySchema( - id: 11, + id: 12, name: r'isMathsEnabled', type: IsarType.bool, ), r'isOneTime': PropertySchema( - id: 12, + id: 13, name: r'isOneTime', type: IsarType.bool, ), r'isPedometerEnabled': PropertySchema( - id: 13, + id: 14, name: r'isPedometerEnabled', type: IsarType.bool, ), + r'isPhotochallengeEnabled': PropertySchema( + id: 15, + name: r'isPhotochallengeEnabled', + type: IsarType.bool, + ), r'isQrEnabled': PropertySchema( - id: 14, + id: 16, name: r'isQrEnabled', type: IsarType.bool, ), r'isShakeEnabled': PropertySchema( - id: 15, + id: 17, name: r'isShakeEnabled', type: IsarType.bool, ), r'isSharedAlarmEnabled': PropertySchema( - id: 16, + id: 18, name: r'isSharedAlarmEnabled', type: IsarType.bool, ), r'isTimer': PropertySchema( - id: 17, + id: 19, name: r'isTimer', type: IsarType.bool, ), r'isWeatherEnabled': PropertySchema( - id: 18, + id: 20, name: r'isWeatherEnabled', type: IsarType.bool, ), r'label': PropertySchema( - id: 19, + id: 21, name: r'label', type: IsarType.string, ), r'lastEditedUserId': PropertySchema( - id: 20, + id: 22, name: r'lastEditedUserId', type: IsarType.string, ), r'location': PropertySchema( - id: 21, + id: 23, name: r'location', type: IsarType.string, ), r'mainAlarmTime': PropertySchema( - id: 22, + id: 24, name: r'mainAlarmTime', type: IsarType.string, ), r'mathsDifficulty': PropertySchema( - id: 23, + id: 25, name: r'mathsDifficulty', type: IsarType.long, ), r'minutesSinceMidnight': PropertySchema( - id: 24, + id: 26, name: r'minutesSinceMidnight', type: IsarType.long, ), r'mutexLock': PropertySchema( - id: 25, + id: 27, name: r'mutexLock', type: IsarType.bool, ), r'note': PropertySchema( - id: 26, + id: 28, name: r'note', type: IsarType.string, ), r'numMathsQuestions': PropertySchema( - id: 27, + id: 29, name: r'numMathsQuestions', type: IsarType.long, ), r'numberOfSteps': PropertySchema( - id: 28, + id: 30, name: r'numberOfSteps', type: IsarType.long, ), r'ownerId': PropertySchema( - id: 29, + id: 31, name: r'ownerId', type: IsarType.string, ), r'ownerName': PropertySchema( - id: 30, + id: 32, name: r'ownerName', type: IsarType.string, ), r'qrValue': PropertySchema( - id: 31, + id: 33, name: r'qrValue', type: IsarType.string, ), r'ringtoneName': PropertySchema( - id: 32, + id: 34, name: r'ringtoneName', type: IsarType.string, ), r'shakeTimes': PropertySchema( - id: 33, + id: 35, name: r'shakeTimes', type: IsarType.long, ), r'sharedUserIds': PropertySchema( - id: 34, + id: 36, name: r'sharedUserIds', type: IsarType.stringList, ), r'showMotivationalQuote': PropertySchema( - id: 35, + id: 37, name: r'showMotivationalQuote', type: IsarType.bool, ), r'snoozeDuration': PropertySchema( - id: 36, + id: 38, name: r'snoozeDuration', type: IsarType.long, ), r'volMax': PropertySchema( - id: 37, + id: 39, name: r'volMax', type: IsarType.double, ), r'volMin': PropertySchema( - id: 38, + id: 40, name: r'volMin', type: IsarType.double, ), r'weatherTypes': PropertySchema( - id: 39, + id: 41, name: r'weatherTypes', type: IsarType.longList, ) @@ -247,6 +257,7 @@ int _alarmModelEstimateSize( bytesCount += 3 + value.length * 3; } } + bytesCount += 3 + object.imageurl.length * 3; bytesCount += 3 + object.label.length * 3; bytesCount += 3 + object.lastEditedUserId.length * 3; bytesCount += 3 + object.location.length * 3; @@ -290,39 +301,41 @@ void _alarmModelSerialize( writer.writeBool(offsets[4], object.deleteAfterGoesOff); writer.writeString(offsets[5], object.firestoreId); writer.writeLong(offsets[6], object.gradient); - writer.writeLong(offsets[7], object.intervalToAlarm); - writer.writeBool(offsets[8], object.isActivityEnabled); - writer.writeBool(offsets[9], object.isEnabled); - writer.writeBool(offsets[10], object.isLocationEnabled); - writer.writeBool(offsets[11], object.isMathsEnabled); - writer.writeBool(offsets[12], object.isOneTime); - writer.writeBool(offsets[13], object.isPedometerEnabled); - writer.writeBool(offsets[14], object.isQrEnabled); - writer.writeBool(offsets[15], object.isShakeEnabled); - writer.writeBool(offsets[16], object.isSharedAlarmEnabled); - writer.writeBool(offsets[17], object.isTimer); - writer.writeBool(offsets[18], object.isWeatherEnabled); - writer.writeString(offsets[19], object.label); - writer.writeString(offsets[20], object.lastEditedUserId); - writer.writeString(offsets[21], object.location); - writer.writeString(offsets[22], object.mainAlarmTime); - writer.writeLong(offsets[23], object.mathsDifficulty); - writer.writeLong(offsets[24], object.minutesSinceMidnight); - writer.writeBool(offsets[25], object.mutexLock); - writer.writeString(offsets[26], object.note); - writer.writeLong(offsets[27], object.numMathsQuestions); - writer.writeLong(offsets[28], object.numberOfSteps); - writer.writeString(offsets[29], object.ownerId); - writer.writeString(offsets[30], object.ownerName); - writer.writeString(offsets[31], object.qrValue); - writer.writeString(offsets[32], object.ringtoneName); - writer.writeLong(offsets[33], object.shakeTimes); - writer.writeStringList(offsets[34], object.sharedUserIds); - writer.writeBool(offsets[35], object.showMotivationalQuote); - writer.writeLong(offsets[36], object.snoozeDuration); - writer.writeDouble(offsets[37], object.volMax); - writer.writeDouble(offsets[38], object.volMin); - writer.writeLongList(offsets[39], object.weatherTypes); + writer.writeString(offsets[7], object.imageurl); + writer.writeLong(offsets[8], object.intervalToAlarm); + writer.writeBool(offsets[9], object.isActivityEnabled); + writer.writeBool(offsets[10], object.isEnabled); + writer.writeBool(offsets[11], object.isLocationEnabled); + writer.writeBool(offsets[12], object.isMathsEnabled); + writer.writeBool(offsets[13], object.isOneTime); + writer.writeBool(offsets[14], object.isPedometerEnabled); + writer.writeBool(offsets[15], object.isPhotochallengeEnabled); + writer.writeBool(offsets[16], object.isQrEnabled); + writer.writeBool(offsets[17], object.isShakeEnabled); + writer.writeBool(offsets[18], object.isSharedAlarmEnabled); + writer.writeBool(offsets[19], object.isTimer); + writer.writeBool(offsets[20], object.isWeatherEnabled); + writer.writeString(offsets[21], object.label); + writer.writeString(offsets[22], object.lastEditedUserId); + writer.writeString(offsets[23], object.location); + writer.writeString(offsets[24], object.mainAlarmTime); + writer.writeLong(offsets[25], object.mathsDifficulty); + writer.writeLong(offsets[26], object.minutesSinceMidnight); + writer.writeBool(offsets[27], object.mutexLock); + writer.writeString(offsets[28], object.note); + writer.writeLong(offsets[29], object.numMathsQuestions); + writer.writeLong(offsets[30], object.numberOfSteps); + writer.writeString(offsets[31], object.ownerId); + writer.writeString(offsets[32], object.ownerName); + writer.writeString(offsets[33], object.qrValue); + writer.writeString(offsets[34], object.ringtoneName); + writer.writeLong(offsets[35], object.shakeTimes); + writer.writeStringList(offsets[36], object.sharedUserIds); + writer.writeBool(offsets[37], object.showMotivationalQuote); + writer.writeLong(offsets[38], object.snoozeDuration); + writer.writeDouble(offsets[39], object.volMax); + writer.writeDouble(offsets[40], object.volMin); + writer.writeLongList(offsets[41], object.weatherTypes); } AlarmModel _alarmModelDeserialize( @@ -338,39 +351,41 @@ AlarmModel _alarmModelDeserialize( days: reader.readBoolList(offsets[3]) ?? [], deleteAfterGoesOff: reader.readBool(offsets[4]), gradient: reader.readLong(offsets[6]), - intervalToAlarm: reader.readLong(offsets[7]), - isActivityEnabled: reader.readBool(offsets[8]), - isEnabled: reader.readBoolOrNull(offsets[9]) ?? true, - isLocationEnabled: reader.readBool(offsets[10]), - isMathsEnabled: reader.readBool(offsets[11]), - isOneTime: reader.readBool(offsets[12]), - isPedometerEnabled: reader.readBool(offsets[13]), - isQrEnabled: reader.readBool(offsets[14]), - isShakeEnabled: reader.readBool(offsets[15]), - isSharedAlarmEnabled: reader.readBool(offsets[16]), - isTimer: reader.readBool(offsets[17]), - isWeatherEnabled: reader.readBool(offsets[18]), - label: reader.readString(offsets[19]), - lastEditedUserId: reader.readString(offsets[20]), - location: reader.readString(offsets[21]), - mainAlarmTime: reader.readStringOrNull(offsets[22]), - mathsDifficulty: reader.readLong(offsets[23]), - minutesSinceMidnight: reader.readLong(offsets[24]), - mutexLock: reader.readBool(offsets[25]), - note: reader.readString(offsets[26]), - numMathsQuestions: reader.readLong(offsets[27]), - numberOfSteps: reader.readLong(offsets[28]), - ownerId: reader.readString(offsets[29]), - ownerName: reader.readString(offsets[30]), - qrValue: reader.readString(offsets[31]), - ringtoneName: reader.readString(offsets[32]), - shakeTimes: reader.readLong(offsets[33]), - sharedUserIds: reader.readStringList(offsets[34]), - showMotivationalQuote: reader.readBool(offsets[35]), - snoozeDuration: reader.readLong(offsets[36]), - volMax: reader.readDouble(offsets[37]), - volMin: reader.readDouble(offsets[38]), - weatherTypes: reader.readLongList(offsets[39]) ?? [], + imageurl: reader.readString(offsets[7]), + intervalToAlarm: reader.readLong(offsets[8]), + isActivityEnabled: reader.readBool(offsets[9]), + isEnabled: reader.readBoolOrNull(offsets[10]) ?? true, + isLocationEnabled: reader.readBool(offsets[11]), + isMathsEnabled: reader.readBool(offsets[12]), + isOneTime: reader.readBool(offsets[13]), + isPedometerEnabled: reader.readBool(offsets[14]), + isPhotochallengeEnabled: reader.readBool(offsets[15]), + isQrEnabled: reader.readBool(offsets[16]), + isShakeEnabled: reader.readBool(offsets[17]), + isSharedAlarmEnabled: reader.readBool(offsets[18]), + isTimer: reader.readBool(offsets[19]), + isWeatherEnabled: reader.readBool(offsets[20]), + label: reader.readString(offsets[21]), + lastEditedUserId: reader.readString(offsets[22]), + location: reader.readString(offsets[23]), + mainAlarmTime: reader.readStringOrNull(offsets[24]), + mathsDifficulty: reader.readLong(offsets[25]), + minutesSinceMidnight: reader.readLong(offsets[26]), + mutexLock: reader.readBool(offsets[27]), + note: reader.readString(offsets[28]), + numMathsQuestions: reader.readLong(offsets[29]), + numberOfSteps: reader.readLong(offsets[30]), + ownerId: reader.readString(offsets[31]), + ownerName: reader.readString(offsets[32]), + qrValue: reader.readString(offsets[33]), + ringtoneName: reader.readString(offsets[34]), + shakeTimes: reader.readLong(offsets[35]), + sharedUserIds: reader.readStringList(offsets[36]), + showMotivationalQuote: reader.readBool(offsets[37]), + snoozeDuration: reader.readLong(offsets[38]), + volMax: reader.readDouble(offsets[39]), + volMin: reader.readDouble(offsets[40]), + weatherTypes: reader.readLongList(offsets[41]) ?? [], ); object.firestoreId = reader.readStringOrNull(offsets[5]); object.isarId = id; @@ -399,13 +414,13 @@ P _alarmModelDeserializeProp

( case 6: return (reader.readLong(offset)) as P; case 7: - return (reader.readLong(offset)) as P; + return (reader.readString(offset)) as P; case 8: - return (reader.readBool(offset)) as P; + return (reader.readLong(offset)) as P; case 9: - return (reader.readBoolOrNull(offset) ?? true) as P; - case 10: return (reader.readBool(offset)) as P; + case 10: + return (reader.readBoolOrNull(offset) ?? true) as P; case 11: return (reader.readBool(offset)) as P; case 12: @@ -423,46 +438,50 @@ P _alarmModelDeserializeProp

( case 18: return (reader.readBool(offset)) as P; case 19: - return (reader.readString(offset)) as P; + return (reader.readBool(offset)) as P; case 20: - return (reader.readString(offset)) as P; + return (reader.readBool(offset)) as P; case 21: return (reader.readString(offset)) as P; case 22: - return (reader.readStringOrNull(offset)) as P; + return (reader.readString(offset)) as P; case 23: - return (reader.readLong(offset)) as P; + return (reader.readString(offset)) as P; case 24: - return (reader.readLong(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 25: - return (reader.readBool(offset)) as P; + return (reader.readLong(offset)) as P; case 26: - return (reader.readString(offset)) as P; - case 27: return (reader.readLong(offset)) as P; + case 27: + return (reader.readBool(offset)) as P; case 28: - return (reader.readLong(offset)) as P; - case 29: return (reader.readString(offset)) as P; + case 29: + return (reader.readLong(offset)) as P; case 30: - return (reader.readString(offset)) as P; + return (reader.readLong(offset)) as P; case 31: return (reader.readString(offset)) as P; case 32: return (reader.readString(offset)) as P; case 33: - return (reader.readLong(offset)) as P; + return (reader.readString(offset)) as P; case 34: - return (reader.readStringList(offset)) as P; + return (reader.readString(offset)) as P; case 35: - return (reader.readBool(offset)) as P; - case 36: return (reader.readLong(offset)) as P; + case 36: + return (reader.readStringList(offset)) as P; case 37: - return (reader.readDouble(offset)) as P; + return (reader.readBool(offset)) as P; case 38: - return (reader.readDouble(offset)) as P; + return (reader.readLong(offset)) as P; case 39: + return (reader.readDouble(offset)) as P; + case 40: + return (reader.readDouble(offset)) as P; + case 41: return (reader.readLongList(offset) ?? []) as P; default: throw IsarError('Unknown property with id $propertyId'); @@ -1200,6 +1219,140 @@ extension AlarmModelQueryFilter }); } + QueryBuilder imageurlEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'imageurl', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + imageurlGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'imageurl', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder imageurlLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'imageurl', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder imageurlBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'imageurl', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + imageurlStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'imageurl', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder imageurlEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'imageurl', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder imageurlContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'imageurl', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder imageurlMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'imageurl', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + imageurlIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'imageurl', + value: '', + )); + }); + } + + QueryBuilder + imageurlIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'imageurl', + value: '', + )); + }); + } + QueryBuilder intervalToAlarmEqualTo(int value) { return QueryBuilder.apply(this, (query) { @@ -1316,6 +1469,16 @@ extension AlarmModelQueryFilter }); } + QueryBuilder + isPhotochallengeEnabledEqualTo(bool value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'isPhotochallengeEnabled', + value: value, + )); + }); + } + QueryBuilder isQrEnabledEqualTo(bool value) { return QueryBuilder.apply(this, (query) { @@ -3589,6 +3752,18 @@ extension AlarmModelQuerySortBy }); } + QueryBuilder sortByImageurl() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'imageurl', Sort.asc); + }); + } + + QueryBuilder sortByImageurlDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'imageurl', Sort.desc); + }); + } + QueryBuilder sortByIntervalToAlarm() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'intervalToAlarm', Sort.asc); @@ -3679,6 +3854,20 @@ extension AlarmModelQuerySortBy }); } + QueryBuilder + sortByIsPhotochallengeEnabled() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isPhotochallengeEnabled', Sort.asc); + }); + } + + QueryBuilder + sortByIsPhotochallengeEnabledDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isPhotochallengeEnabled', Sort.desc); + }); + } + QueryBuilder sortByIsQrEnabled() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'isQrEnabled', Sort.asc); @@ -4057,6 +4246,18 @@ extension AlarmModelQuerySortThenBy }); } + QueryBuilder thenByImageurl() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'imageurl', Sort.asc); + }); + } + + QueryBuilder thenByImageurlDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'imageurl', Sort.desc); + }); + } + QueryBuilder thenByIntervalToAlarm() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'intervalToAlarm', Sort.asc); @@ -4147,6 +4348,20 @@ extension AlarmModelQuerySortThenBy }); } + QueryBuilder + thenByIsPhotochallengeEnabled() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isPhotochallengeEnabled', Sort.asc); + }); + } + + QueryBuilder + thenByIsPhotochallengeEnabledDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isPhotochallengeEnabled', Sort.desc); + }); + } + QueryBuilder thenByIsQrEnabled() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'isQrEnabled', Sort.asc); @@ -4508,6 +4723,13 @@ extension AlarmModelQueryWhereDistinct }); } + QueryBuilder distinctByImageurl( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'imageurl', caseSensitive: caseSensitive); + }); + } + QueryBuilder distinctByIntervalToAlarm() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'intervalToAlarm'); @@ -4553,6 +4775,13 @@ extension AlarmModelQueryWhereDistinct }); } + QueryBuilder + distinctByIsPhotochallengeEnabled() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'isPhotochallengeEnabled'); + }); + } + QueryBuilder distinctByIsQrEnabled() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'isQrEnabled'); @@ -4776,6 +5005,12 @@ extension AlarmModelQueryProperty }); } + QueryBuilder imageurlProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'imageurl'); + }); + } + QueryBuilder intervalToAlarmProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'intervalToAlarm'); @@ -4819,6 +5054,13 @@ extension AlarmModelQueryProperty }); } + QueryBuilder + isPhotochallengeEnabledProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'isPhotochallengeEnabled'); + }); + } + QueryBuilder isQrEnabledProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'isQrEnabled'); diff --git a/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart b/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart index 0e4a930a..9f26ca51 100644 --- a/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart +++ b/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart @@ -1,10 +1,12 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; +// import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:get/get.dart'; import 'package:fl_location/fl_location.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:latlong2/latlong.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:path_provider/path_provider.dart'; @@ -59,9 +61,15 @@ class AddOrUpdateAlarmController extends GetxController { facing: CameraFacing.back, torchEnabled: false, ); - final qrValue = ''.obs; + final qrValue = ''.obs; // qrvalue stored in alarm + final detectedQrValue = ''.obs; // QR value detected by camera final isQrEnabled = false.obs; + //photochallenge + final imageurl = ''.obs; + final imageFile = File('').obs; + final isPhotochallengeEnabled = false.obs; + final mathsSliderValue = 0.0.obs; final mathsDifficulty = Difficulty.Easy.obs; final isMathsEnabled = false.obs; @@ -89,6 +97,7 @@ class AddOrUpdateAlarmController extends GetxController { final RxDouble selectedGradientDouble = 0.0.obs; final RxDouble volMin = 0.0.obs; final RxDouble volMax = 10.0.obs; + final picker = ImagePicker(); final RxInt hours = 0.obs, minutes = 0.obs, meridiemIndex = 0.obs; final List meridiem = ['AM'.obs, 'PM'.obs]; @@ -108,6 +117,10 @@ class AddOrUpdateAlarmController extends GetxController { RxBool isCustomSelected = false.obs; RxBool isPlaying = false.obs; // Observable boolean to track playing state + // to check whether alarm data is updated or not + Map initialValues = {}; + Map changedFields = {}; + void toggleIsPlaying() { isPlaying.toggle(); } @@ -125,7 +138,7 @@ class AddOrUpdateAlarmController extends GetxController { } void setGradient(int value) { - this.gradient.value = value; + gradient.value = value; } void setIsWeekdaysSelected(bool value) { @@ -137,7 +150,7 @@ class AddOrUpdateAlarmController extends GetxController { } void setIsCustomSelected(bool value) { - isCustomSelected.value = true; + isCustomSelected.value = value; if (value == true) { isWeekdaysSelected.value = false; isDailySelected.value = false; @@ -189,24 +202,28 @@ class AddOrUpdateAlarmController extends GetxController { onPressed: () async { Get.back(); - // Request overlay permission - if (!(await Permission.systemAlertWindow.isGranted)) { - final status = await Permission.systemAlertWindow.request(); - if (!status.isGranted) { - debugPrint('SYSTEM_ALERT_WINDOW permission denied!'); - return; + if (Platform.isAndroid) { + // Request overlay permission + if (!(await Permission.systemAlertWindow.isGranted)) { + final status = await Permission.systemAlertWindow.request(); + if (!status.isGranted) { + debugPrint('SYSTEM_ALERT_WINDOW permission denied!'); + return; + } } - } - if (!(await Permission.ignoreBatteryOptimizations.isGranted)) { - bool requested = await Permission.ignoreBatteryOptimizations - .request() - .isGranted; - if (!requested) { - debugPrint('IGNORE_BATTERY_OPTIMIZATION permission denied!'); - return; + if (!(await Permission.ignoreBatteryOptimizations.isGranted)) { + bool requested = await Permission.ignoreBatteryOptimizations + .request() + .isGranted; + if (!requested) { + debugPrint( + 'IGNORE_BATTERY_OPTIMIZATION permission denied!'); + return; + } } } + // Request notification permission if (!await Permission.notification.isGranted) { final status = await Permission.notification.request(); @@ -226,6 +243,80 @@ class AddOrUpdateAlarmController extends GetxController { } } + void checkUnsavedChangesAndNavigate(BuildContext context) { + int numberOfChangesMade = + changedFields.entries.where((element) => element.value == true).length; + if (numberOfChangesMade >= 1) { + Get.defaultDialog( + titlePadding: const EdgeInsets.symmetric( + vertical: 20, + ), + backgroundColor: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + title: 'Discard Changes?'.tr, + titleStyle: Theme.of(context).textTheme.displaySmall, + content: Column( + children: [ + Text( + 'unsavedChanges'.tr, + style: Theme.of(context).textTheme.bodyMedium, + textAlign: TextAlign.center, + ), + Padding( + padding: const EdgeInsets.only( + top: 20, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: () { + Get.back(); + }, + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'Cancel'.tr, + style: Theme.of(context).textTheme.displaySmall!.copyWith( + color: kprimaryBackgroundColor, + ), + ), + ), + OutlinedButton( + onPressed: () { + Get.back(closeOverlays: true); + Get.back(); + }, + style: OutlinedButton.styleFrom( + side: BorderSide( + color: themeController.isLightMode.value + ? Colors.red.withOpacity(0.9) + : Colors.red, + width: 1, + ), + ), + child: Text( + 'Leave'.tr, + style: Theme.of(context).textTheme.displaySmall!.copyWith( + color: themeController.isLightMode.value + ? Colors.red.withOpacity(0.9) + : Colors.red, + ), + ), + ), + ], + ), + ), + ], + ), + ); + } else { + Get.back(); + } + } + Future getLocation() async { if (await _checkAndRequestPermission()) { const timeLimit = Duration(seconds: 10); @@ -328,7 +419,7 @@ class AddOrUpdateAlarmController extends GetxController { } showQRDialog() { - restartQRCodeController(); + restartQRCodeController(false); Get.defaultDialog( titlePadding: const EdgeInsets.symmetric(vertical: 20), backgroundColor: themeController.isLightMode.value @@ -339,7 +430,7 @@ class AddOrUpdateAlarmController extends GetxController { content: Obx( () => Column( children: [ - isQrEnabled.value == false + detectedQrValue.value.isEmpty ? SizedBox( height: 300, width: 300, @@ -349,18 +440,17 @@ class AddOrUpdateAlarmController extends GetxController { onDetect: (capture) { final List barcodes = capture.barcodes; for (final barcode in barcodes) { - qrValue.value = barcode.rawValue.toString(); + detectedQrValue.value = barcode.rawValue.toString(); debugPrint(barcode.rawValue.toString()); - isQrEnabled.value = true; } }, ), ) : Padding( padding: const EdgeInsets.only(bottom: 15.0), - child: Text(qrValue.value), + child: Text(detectedQrValue.value), ), - isQrEnabled.value == true + (detectedQrValue.value.isNotEmpty) ? Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -381,6 +471,8 @@ class AddOrUpdateAlarmController extends GetxController { ), ), onPressed: () { + qrValue.value = detectedQrValue.value; + isQrEnabled.value = true; Get.back(); }, ), @@ -402,10 +494,32 @@ class AddOrUpdateAlarmController extends GetxController { ), onPressed: () async { qrController.dispose(); - restartQRCodeController(); - isQrEnabled.value = false; + restartQRCodeController(true); }, ), + if (isQrEnabled.value) + TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'Disable', + style: Theme.of(Get.context!) + .textTheme + .displaySmall! + .copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : ksecondaryTextColor, + ), + ), + onPressed: () { + isQrEnabled.value = false; + qrValue.value = ''; + Get.back(); + }, + ), ], ) : const SizedBox(), @@ -494,7 +608,7 @@ class AddOrUpdateAlarmController extends GetxController { } } - restartQRCodeController() async { + restartQRCodeController(bool retake) async { // Camera permission already granted, proceed with QR code scanning qrController = MobileScannerController( autoStart: true, @@ -502,6 +616,263 @@ class AddOrUpdateAlarmController extends GetxController { facing: CameraFacing.back, torchEnabled: false, ); + detectedQrValue.value = retake ? '' : qrValue.value; + } + + requestPhotoPermission(context) async { + PermissionStatus cameraStatus = await Permission.camera.status; + + if (!cameraStatus.isGranted) { + Get.defaultDialog( + backgroundColor: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + title: 'Camera Permission'.tr, + titleStyle: TextStyle( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : Colors.white, + ), + titlePadding: const EdgeInsets.only( + top: 25, + left: 10, + ), + contentPadding: const EdgeInsets.only(top: 20, left: 20, bottom: 23), + content: Text('Please allow camera access for capturing photo.'.tr), + onCancel: () { + Get.back(); // Close the alert box + }, + onConfirm: () async { + Get.back(); // Close the alert box + PermissionStatus permissionStatus = await Permission.camera.request(); + if (permissionStatus.isGranted) { + // Permission granted, proceed with QR code scanning + showPhotoDialog(); + } + }, + confirm: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'OK', + style: Theme.of(context).textTheme.displaySmall!.copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : ksecondaryTextColor, + ), + ), + onPressed: () async { + Get.back(); // Close the alert box + PermissionStatus permissionStatus = + await Permission.camera.request(); + if (permissionStatus.isGranted) { + // Permission granted, proceed with QR code scanning + showPhotoDialog(); + } + }, + ), + cancel: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.5) + : kprimaryTextColor.withOpacity(0.5), + ), + ), + child: Text( + 'Cancel', + style: Theme.of(context).textTheme.displaySmall!.copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor, + ), + ), + onPressed: () { + Get.back(); // Close the alert box + }, + ), + ); + } else { + showPhotoDialog(); + } + } + + Future _uploadImageToStorage(File image) async { + /* + // Code for storing Photo in firestore + final firebaseStorage = FirebaseStorage.instance; + Reference ref = firebaseStorage.ref().child(alarmID); + + UploadTask tsk = ref.putFile(image); + TaskSnapshot snap = await tsk; + Future dowloadurl = snap.ref.getDownloadURL(); + + return dowloadurl; + + + */ + try { + Directory documentsDirectory = await getApplicationDocumentsDirectory(); + String photosDirectoryPath = '${documentsDirectory.path}/photos'; + + // Create the ringtones directory if it doesn't exist + Directory(photosDirectoryPath).createSync(recursive: true); + + // Copy the picked audio files to the ringtones directory + String filePath = image.path; + File pickedFile = File(filePath); + String newFilePath = '$photosDirectoryPath/$alarmID'; + + if (imageurl.value == '') { + pickedFile.copySync(newFilePath); + debugPrint(newFilePath); + + return newFilePath; + } else { + // Assuming imageurl.value already contains the full path, + // so create directories + + pickedFile.copySync(imageurl.value); + debugPrint(imageurl.value); + return imageurl.value; + } + } catch (e) { + debugPrint(e.toString()); + return ''; + } + } + + showPhotoDialog() async { + if (isPhotochallengeEnabled.value == false) { + final pickedFile = await picker.pickImage(source: ImageSource.camera); + if (pickedFile != null) { + File imagepickedfile = File(pickedFile.path); + imageurl.value = await _uploadImageToStorage(imagepickedfile); + + //clear image chache + await imagepickedfile.delete(); + imageFile.value = File(imageurl.value); + isPhotochallengeEnabled.value = true; + } else {} + } else { + Get.defaultDialog( + titlePadding: const EdgeInsets.symmetric(vertical: 20), + backgroundColor: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + title: 'Capture a Photo'.tr, + titleStyle: Theme.of(Get.context!).textTheme.displaySmall, + content: Obx( + () => Column( + children: [ + (isPhotochallengeEnabled.value) + ? Padding( + padding: const EdgeInsets.only(bottom: 15.0), + child: Image.file( + File(imageurl.value), + fit: BoxFit.cover, + height: MediaQuery.of(Get.context!).size.height * 0.3, + width: MediaQuery.of(Get.context!).size.width, + ), + ) + : const Text('Photo Challenge Disabled'), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'Save'.tr, + style: Theme.of(Get.context!) + .textTheme + .displaySmall! + .copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : ksecondaryTextColor, + ), + ), + onPressed: () { + Get.back(); + }, + ), + TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'Retake'.tr, + style: Theme.of(Get.context!) + .textTheme + .displaySmall! + .copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : ksecondaryTextColor, + ), + ), + onPressed: () async { + // showPhotoDialog(); + final pickedFile = + await picker.pickImage(source: ImageSource.camera); + + if (await File(imageurl.value).exists()) { + await File(imageurl.value).delete(); + } + if (pickedFile != null) { + File imagepickedfile = File(pickedFile.path); + + imageurl.value = + await _uploadImageToStorage(imagepickedfile); + + //clear image chache + await imagepickedfile.delete(); + isPhotochallengeEnabled.value = true; + Get.back(); + } else {} + }, + ), + if (isPhotochallengeEnabled.value) + TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'Disable'.tr, + style: Theme.of(Get.context!) + .textTheme + .displaySmall! + .copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : ksecondaryTextColor, + ), + ), + onPressed: () async { + isPhotochallengeEnabled.value = false; + File file = File(imageurl.value); + + if (await file.exists()) { + await file.delete(); + debugPrint('File deleted successfully.'); + } else { + debugPrint('File does not exist.'); + } + imageurl.value = ''; + Get.back(); + }, + ), + ], + ), + ], + ), + ), + ); + } } updateAlarm(AlarmModel alarmData) async { @@ -525,7 +896,9 @@ class AddOrUpdateAlarmController extends GetxController { } else { // Deleting alarm on firestore to ensure no duplicate entry await FirestoreDb.deleteAlarm( - userModel.value, alarmRecord!.firestoreId!); + userModel.value, + alarmRecord!.firestoreId!, + ); createAlarm(alarmData); } } @@ -548,7 +921,8 @@ class AddOrUpdateAlarmController extends GetxController { lastEditedUserId = userModel.value!.id; } - // listens to the userModel declared in homeController and updates on signup event + // listens to the userModel declared in homeController + //and updates on signup event homeController.userModel.stream.listen((UserModel? user) { userModel.value = user; if (user != null) { @@ -635,6 +1009,12 @@ class AddOrUpdateAlarmController extends GetxController { isQrEnabled.value = alarmRecord!.isQrEnabled; qrValue.value = alarmRecord!.qrValue; + detectedQrValue.value = alarmRecord!.qrValue; + + isPhotochallengeEnabled.value = alarmRecord!.isPhotochallengeEnabled; + imageurl.value = alarmRecord!.imageurl; + + imageFile.value = File(imageurl.value); alarmID = alarmRecord!.alarmID; ownerId = alarmRecord!.ownerId; @@ -691,6 +1071,85 @@ class AddOrUpdateAlarmController extends GetxController { repeatDays, ); + // store initial values of the variables + initialValues.addAll({ + 'selectedTime': selectedTime.value, + 'daysRepeating': daysRepeating.value, + 'snoozeDuration': snoozeDuration.value, + 'deleteAfterGoesOff': deleteAfterGoesOff.value, + 'label': label.value, + 'note': note.value, + 'customRingtoneName': customRingtoneName.value, + 'volMin': volMin.value, + 'volMax': volMax.value, + 'gradient': gradient.value, + 'showMotivationalQuote': showMotivationalQuote.value, + 'activityInterval': activityInterval.value, + 'weatherTypes': weatherTypes.value, + 'location': + '${selectedPoint.value.latitude} ${selectedPoint.value.longitude}', + 'shakeTimes': shakeTimes.value, + 'qrValue': qrValue.value, + 'mathsDifficulty': mathsDifficulty.value, + 'mathsSliderValue': mathsSliderValue.value, + 'numMathsQuestions': numMathsQuestions.value, + 'numberOfSteps': numberOfSteps.value, + 'isSharedAlarmEnabled': isSharedAlarmEnabled.value, + 'offsetDuration': offsetDuration.value, + 'isOffsetBefore': isOffsetBefore.value + }); + + addListeners(); + + if (await SecureStorageProvider().retrieveApiKey(ApiKeys.openWeatherMap) != + null) { + weatherApiKeyExists.value = true; + } + + // If there's an argument sent, we are in update mode + } + + void addListeners() { + // Updating UI to show time to alarm + selectedTime.listen((time) { + debugPrint('CHANGED CHANGED CHANGED CHANGED'); + timeToAlarm.value = + Utils.timeUntilAlarm(TimeOfDay.fromDateTime(time), repeatDays); + _compareAndSetChange('selectedTime', time); + }); + + //Updating UI to show repeated days + repeatDays.listen((days) { + daysRepeating.value = Utils.getRepeatDays(days); + _compareAndSetChange('daysRepeating', daysRepeating.value); + }); + + setupListener(snoozeDuration, 'snoozeDuration'); + setupListener(deleteAfterGoesOff, 'deleteAfterGoesOff'); + setupListener(label, 'label'); + setupListener(note, 'note'); + setupListener(customRingtoneName, 'customRingtoneName'); + setupListener(volMin, 'volMin'); + setupListener(volMax, 'volMax'); + setupListener(gradient, 'gradient'); + setupListener(showMotivationalQuote, 'showMotivationalQuote'); + setupListener(activityInterval, 'activityInterval'); + + // Updating UI to show weather types + selectedWeather.listen((weather) { + if (weather.toList().isEmpty) { + isWeatherEnabled.value = false; + } else { + isWeatherEnabled.value = true; + } + weatherTypes.value = Utils.getFormattedWeatherTypes(weather); + _compareAndSetChange('weatherTypes', weatherTypes.value); + // if location based is disabled and weather based is disabled, reset location + if (weatherTypes.value == 'Off' && !isLocationEnabled.value) { + selectedPoint.value = LatLng(0, 0); + } + }); + // Adding to markers list, to display on map // (MarkersLayer takes only List) selectedPoint.listen( @@ -707,38 +1166,44 @@ class AddOrUpdateAlarmController extends GetxController { ), ), ); + _compareAndSetChange( + 'location', '${point.latitude} ${point.longitude}'); }, ); - // Updating UI to show time to alarm - - selectedTime.listen((time) { - debugPrint('CHANGED CHANGED CHANGED CHANGED'); - timeToAlarm.value = - Utils.timeUntilAlarm(TimeOfDay.fromDateTime(time), repeatDays); + // reset selectedPoint to default value if isLocationEnabled is false and weather based is off + isLocationEnabled.listen((value) { + if (!value && weatherTypes.value == 'Off') { + selectedPoint.value = LatLng(0, 0); + } }); - //Updating UI to show repeated days - repeatDays.listen((days) { - daysRepeating.value = Utils.getRepeatDays(days); - }); + setupListener(shakeTimes, 'shakeTimes'); + setupListener(qrValue, 'qrValue'); + setupListener(mathsSliderValue, 'mathsSliderValue'); + setupListener(mathsDifficulty, 'mathsDifficulty'); + setupListener(numMathsQuestions, 'numMathsQuestions'); + setupListener(numberOfSteps, 'numberOfSteps'); - // Updating UI to show weather types - selectedWeather.listen((weather) { - if (weather.toList().isEmpty) { - isWeatherEnabled.value = false; - } else { - isWeatherEnabled.value = true; - } - weatherTypes.value = Utils.getFormattedWeatherTypes(weather); + setupListener(isSharedAlarmEnabled, 'isSharedAlarmEnabled'); + setupListener(offsetDuration, 'offsetDuration'); + setupListener(isOffsetBefore, 'isOffsetBefore'); + } + + // adds listener to rxVar variable + void setupListener(Rx rxVar, String fieldName) { + rxVar.listen((value) { + _compareAndSetChange(fieldName, value); }); + } - if (await SecureStorageProvider().retrieveApiKey(ApiKeys.openWeatherMap) != - null) { - weatherApiKeyExists.value = true; + // if initialValues map contains fieldName and newValue is equal to currentValue + // then set changeFields map field to true + void _compareAndSetChange(String fieldName, dynamic currentValue) { + if (initialValues.containsKey(fieldName)) { + bool hasChanged = initialValues[fieldName] != currentValue; + changedFields[fieldName] = hasChanged; } - - // If there's an argument sent, we are in update mode } @override @@ -796,6 +1261,8 @@ class AddOrUpdateAlarmController extends GetxController { isSharedAlarmEnabled: isSharedAlarmEnabled.value, isQrEnabled: isQrEnabled.value, qrValue: qrValue.value, + isPhotochallengeEnabled: isPhotochallengeEnabled.value, + imageurl: imageurl.value, isMathsEnabled: isMathsEnabled.value, numMathsQuestions: numMathsQuestions.value, mathsDifficulty: mathsDifficulty.value.index, diff --git a/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart b/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart index 7888ad57..6b7dc30a 100644 --- a/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart +++ b/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart @@ -3,14 +3,20 @@ import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/settings_controller.dart'; +import 'package:ultimate_alarm_clock/app/modules/timer/controllers/timer_controller.dart'; class InputTimeController extends GetxController { AddOrUpdateAlarmController addOrUpdateAlarmController = Get.find(); + TimerController timerController = Get.find(); SettingsController settingsController = Get.find(); final isTimePicker = false.obs; + final isTimePickerTimer = false.obs; TextEditingController inputHrsController = TextEditingController(); TextEditingController inputMinutesController = TextEditingController(); + TextEditingController inputHoursControllerTimer = TextEditingController(); + TextEditingController inputMinutesControllerTimer = TextEditingController(); + TextEditingController inputSecondsControllerTimer = TextEditingController(); final selectedDateTime = DateTime.now().obs; bool isInputtingTime = false; @@ -22,6 +28,7 @@ class InputTimeController extends GetxController { @override void onInit() { isTimePicker.value = true; + isTimePickerTimer.value = true; selectedDateTime.value = addOrUpdateAlarmController.selectedTime.value; isAM.value = addOrUpdateAlarmController.selectedTime.value.hour < 12; inputHrsController.text = settingsController.is24HrsEnabled.value @@ -32,6 +39,9 @@ class InputTimeController extends GetxController { ? (selectedDateTime.value.hour - 12).toString() : selectedDateTime.value.hour.toString())); inputMinutesController.text = selectedDateTime.value.minute.toString(); + inputHoursControllerTimer.text = timerController.hours.value.toString(); + inputMinutesControllerTimer.text = timerController.minutes.value.toString(); + inputSecondsControllerTimer.text = timerController.seconds.value.toString(); super.onInit(); } @@ -44,6 +54,10 @@ class InputTimeController extends GetxController { isTimePicker.value = !isTimePicker.value; } + changeTimePickerTimer() { + isTimePickerTimer.value = !isTimePickerTimer.value; + } + int convert24(int value) { if (!settingsController.is24HrsEnabled.value) { if (addOrUpdateAlarmController.meridiemIndex == 0) { @@ -95,7 +109,7 @@ class InputTimeController extends GetxController { addOrUpdateAlarmController.hours.value = 12; } else if (selectedDateTime.value.hour > 12) { addOrUpdateAlarmController.hours.value = - (selectedDateTime.value.hour-12); + (selectedDateTime.value.hour - 12); } else { addOrUpdateAlarmController.hours.value = selectedDateTime.value.hour; } @@ -114,10 +128,27 @@ class InputTimeController extends GetxController { } } + void setTimerTime() { + try { + int hours = int.parse(inputHoursControllerTimer.text); + int minutes = int.parse(inputMinutesControllerTimer.text); + int seconds = int.parse(inputSecondsControllerTimer.text); + + timerController.hours.value = hours; + timerController.minutes.value = minutes; + timerController.seconds.value = seconds; + } catch (e) { + debugPrint(e.toString()); + } + } + @override void onClose() { inputHrsController.dispose(); inputMinutesController.dispose(); + inputHoursControllerTimer.dispose(); + inputMinutesControllerTimer.dispose(); + inputSecondsControllerTimer.dispose(); super.onClose(); } } diff --git a/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart b/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart index a2229623..095cc178 100644 --- a/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart +++ b/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -15,6 +17,7 @@ import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/location import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/maths_challenge_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/note.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/pedometer_challenge_tile.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/photo_challenge_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/qr_bar_code_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/quote_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/repeat_once_tile.dart'; @@ -27,7 +30,6 @@ import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/snooze_d import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/weather_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/settings_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; -import 'package:ultimate_alarm_clock/app/routes/app_pages.dart'; import 'package:ultimate_alarm_clock/app/utils/constants.dart'; import 'package:ultimate_alarm_clock/app/utils/utils.dart'; import '../controllers/add_or_update_alarm_controller.dart'; @@ -35,431 +37,502 @@ import '../controllers/add_or_update_alarm_controller.dart'; class AddOrUpdateAlarmView extends GetView { AddOrUpdateAlarmView({Key? key}) : super(key: key); - ThemeController themeController = Get.find(); - InputTimeController inputTimeController = Get.put(InputTimeController()); - SettingsController settingsController = Get.find(); + final ThemeController themeController = Get.find(); + final InputTimeController inputTimeController = + Get.put(InputTimeController()); + final SettingsController settingsController = Get.find(); @override Widget build(BuildContext context) { var width = Get.width; var height = Get.height; return PopScope( - canPop: false, - onPopInvoked: (bool didPop) { - if (didPop) { - return; - } + canPop: false, + onPopInvoked: (bool didPop) { + if (didPop) { + return; + } - Get.defaultDialog( - titlePadding: const EdgeInsets.symmetric( - vertical: 20, - ), - backgroundColor: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - title: 'Discard Changes?'.tr, - titleStyle: Theme.of(context).textTheme.displaySmall, - content: Column( - children: [ - Text( - 'unsavedChanges'.tr, - style: Theme.of(context).textTheme.bodyMedium, - textAlign: TextAlign.center, - ), - Padding( - padding: const EdgeInsets.only( - top: 20, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - TextButton( - onPressed: () { - Get.back(); - }, - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(kprimaryColor), - ), - child: Text( - 'Cancel'.tr, - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - color: kprimaryBackgroundColor, - ), - ), - ), - OutlinedButton( - onPressed: () { - Get.back(closeOverlays: true); - Get.back(); - }, - style: OutlinedButton.styleFrom( - side: BorderSide( - color: themeController.isLightMode.value - ? Colors.red.withOpacity(0.9) - : Colors.red, - width: 1, - ), - ), - child: Text( - 'Leave'.tr, - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - color: themeController.isLightMode.value - ? Colors.red.withOpacity(0.9) - : Colors.red, - ), - ), - ), - ], - ), + Get.defaultDialog( + titlePadding: const EdgeInsets.symmetric( + vertical: 20, + ), + backgroundColor: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + title: 'Discard Changes?'.tr, + titleStyle: Theme.of(context).textTheme.displaySmall, + content: Column( + children: [ + Text( + 'unsavedChanges'.tr, + style: Theme.of(context).textTheme.bodyMedium, + textAlign: TextAlign.center, + ), + Padding( + padding: const EdgeInsets.only( + top: 20, ), - ], - ), - ); - }, - child: Scaffold( - floatingActionButtonLocation: - FloatingActionButtonLocation.centerDocked, - floatingActionButton: (controller.alarmRecord != null && - controller.mutexLock.value == true) - ? const SizedBox() - : Padding( - padding: const EdgeInsets.all(18.0), - child: SizedBox( - height: height * 0.06, - width: width * 0.8, - child: TextButton( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: () { + Get.back(); + }, style: ButtonStyle( backgroundColor: MaterialStateProperty.all(kprimaryColor), ), child: Text( - (controller.alarmRecord == null) - ? 'Save'.tr - : 'Update'.tr, + 'Cancel'.tr, style: Theme.of(context).textTheme.displaySmall!.copyWith( - color: themeController.isLightMode.value - ? kLightPrimaryTextColor - : ksecondaryTextColor, + color: kprimaryBackgroundColor, ), ), - onPressed: () async { - Utils.hapticFeedback(); - if (controller.userModel.value != null) { - controller - .offsetDetails[controller.userModel.value!.id] = { - 'offsettedTime': Utils.timeOfDayToString( - TimeOfDay.fromDateTime( - Utils.calculateOffsetAlarmTime( - controller.selectedTime.value, - controller.isOffsetBefore.value, - controller.offsetDuration.value, + ), + OutlinedButton( + onPressed: () { + Get.back(closeOverlays: true); + Get.back(); + }, + style: OutlinedButton.styleFrom( + side: BorderSide( + color: themeController.isLightMode.value + ? Colors.red.withOpacity(0.9) + : Colors.red, + width: 1, + ), + ), + child: Text( + 'Leave'.tr, + style: + Theme.of(context).textTheme.displaySmall!.copyWith( + color: themeController.isLightMode.value + ? Colors.red.withOpacity(0.9) + : Colors.red, ), - ), - ), - 'offsetDuration': controller.offsetDuration.value, - 'isOffsetBefore': controller.isOffsetBefore.value, - }; - } else { - controller.offsetDetails.value = {}; - } - AlarmModel alarmRecord = AlarmModel( - deleteAfterGoesOff: - controller.deleteAfterGoesOff.value, - snoozeDuration: controller.snoozeDuration.value, - volMax: controller.volMax.value, - volMin: controller.volMin.value, - gradient: controller.gradient.value, - offsetDetails: controller.offsetDetails, - label: controller.label.value, - note: controller.note.value, - showMotivationalQuote: - controller.showMotivationalQuote.value, - isOneTime: controller.isOneTime.value, - lastEditedUserId: controller.lastEditedUserId, - mutexLock: controller.mutexLock.value, - alarmID: controller.alarmID, - ownerId: controller.ownerId, - ownerName: controller.ownerName, - activityInterval: - controller.activityInterval.value * 60000, - days: controller.repeatDays.toList(), - alarmTime: Utils.timeOfDayToString( - TimeOfDay.fromDateTime( - controller.selectedTime.value, - ), + ), + ), + ], + ), + ), + ], + ), + ); + }, + child: Scaffold( + floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, + floatingActionButton: (controller.alarmRecord != null && + controller.mutexLock.value == true) + ? const SizedBox() + : Padding( + padding: const EdgeInsets.all(18.0), + child: SizedBox( + height: height * 0.06, + width: width * 0.8, + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + (controller.alarmRecord == null) + ? 'Save'.tr + : 'Update'.tr, + style: Theme.of(context).textTheme.displaySmall!.copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : ksecondaryTextColor, ), - mainAlarmTime: Utils.timeOfDayToString( + ), + onPressed: () async { + Utils.hapticFeedback(); + if (controller.userModel.value != null) { + controller + .offsetDetails[controller.userModel.value!.id] = { + 'offsettedTime': Utils.timeOfDayToString( TimeOfDay.fromDateTime( - controller.selectedTime.value, + Utils.calculateOffsetAlarmTime( + controller.selectedTime.value, + controller.isOffsetBefore.value, + controller.offsetDuration.value, + ), ), ), - intervalToAlarm: Utils.getMillisecondsToAlarm( - DateTime.now(), + 'offsetDuration': controller.offsetDuration.value, + 'isOffsetBefore': controller.isOffsetBefore.value, + }; + } else { + controller.offsetDetails.value = {}; + } + AlarmModel alarmRecord = AlarmModel( + deleteAfterGoesOff: controller.deleteAfterGoesOff.value, + snoozeDuration: controller.snoozeDuration.value, + volMax: controller.volMax.value, + volMin: controller.volMin.value, + gradient: controller.gradient.value, + offsetDetails: controller.offsetDetails, + label: controller.label.value, + note: controller.note.value, + showMotivationalQuote: + controller.showMotivationalQuote.value, + isOneTime: controller.isOneTime.value, + lastEditedUserId: controller.lastEditedUserId, + mutexLock: controller.mutexLock.value, + alarmID: controller.alarmID, + ownerId: controller.ownerId, + ownerName: controller.ownerName, + activityInterval: + controller.activityInterval.value * 60000, + days: controller.repeatDays.toList(), + alarmTime: Utils.timeOfDayToString( + TimeOfDay.fromDateTime( controller.selectedTime.value, ), - isActivityEnabled: controller.isActivityenabled.value, - minutesSinceMidnight: Utils.timeOfDayToInt( - TimeOfDay.fromDateTime( - controller.selectedTime.value, - ), + ), + mainAlarmTime: Utils.timeOfDayToString( + TimeOfDay.fromDateTime( + controller.selectedTime.value, + ), + ), + intervalToAlarm: Utils.getMillisecondsToAlarm( + DateTime.now(), + controller.selectedTime.value, + ), + isActivityEnabled: controller.isActivityenabled.value, + minutesSinceMidnight: Utils.timeOfDayToInt( + TimeOfDay.fromDateTime( + controller.selectedTime.value, ), - isLocationEnabled: controller.isLocationEnabled.value, - weatherTypes: Utils.getIntFromWeatherTypes( - controller.selectedWeather.toList(), + ), + isLocationEnabled: controller.isLocationEnabled.value, + weatherTypes: Utils.getIntFromWeatherTypes( + controller.selectedWeather.toList(), + ), + isWeatherEnabled: controller.isWeatherEnabled.value, + location: Utils.geoPointToString( + Utils.latLngToGeoPoint( + controller.selectedPoint.value, ), - isWeatherEnabled: controller.isWeatherEnabled.value, - location: Utils.geoPointToString( - Utils.latLngToGeoPoint( - controller.selectedPoint.value, - ), + ), + isSharedAlarmEnabled: + controller.isSharedAlarmEnabled.value, + isQrEnabled: controller.isQrEnabled.value, + qrValue: controller.qrValue.value, + isPhotochallengeEnabled: + controller.isPhotochallengeEnabled.value, + imageurl: controller.imageurl.value, + isMathsEnabled: controller.isMathsEnabled.value, + numMathsQuestions: controller.numMathsQuestions.value, + mathsDifficulty: controller.mathsDifficulty.value.index, + isShakeEnabled: controller.isShakeEnabled.value, + shakeTimes: controller.shakeTimes.value, + isPedometerEnabled: controller.isPedometerEnabled.value, + numberOfSteps: controller.numberOfSteps.value, + ringtoneName: controller.customRingtoneName.value, + isTimer: false, + ); + + // Adding offset details to the database if + // its a shared alarm + if (controller.isSharedAlarmEnabled.value) { + alarmRecord.offsetDetails = controller.offsetDetails; + alarmRecord.mainAlarmTime = Utils.timeOfDayToString( + TimeOfDay.fromDateTime( + controller.selectedTime.value, ), - isSharedAlarmEnabled: - controller.isSharedAlarmEnabled.value, - isQrEnabled: controller.isQrEnabled.value, - qrValue: controller.qrValue.value, - isMathsEnabled: controller.isMathsEnabled.value, - numMathsQuestions: controller.numMathsQuestions.value, - mathsDifficulty: - controller.mathsDifficulty.value.index, - isShakeEnabled: controller.isShakeEnabled.value, - shakeTimes: controller.shakeTimes.value, - isPedometerEnabled: - controller.isPedometerEnabled.value, - numberOfSteps: controller.numberOfSteps.value, - ringtoneName: controller.customRingtoneName.value, - isTimer: false, ); + } - // Adding offset details to the database if - // its a shared alarm - if (controller.isSharedAlarmEnabled.value) { - alarmRecord.offsetDetails = controller.offsetDetails; - alarmRecord.mainAlarmTime = Utils.timeOfDayToString( - TimeOfDay.fromDateTime( - controller.selectedTime.value, - ), - ); - } - - try { - if (controller.alarmRecord == null) { - await controller.createAlarm(alarmRecord); - } else { - AlarmModel updatedAlarmModel = - controller.updatedAlarmModel(); - await controller.updateAlarm(updatedAlarmModel); - } - } catch (e) { - debugPrint(e.toString()); + try { + if (controller.alarmRecord == null) { + await controller.createAlarm(alarmRecord); + } else { + AlarmModel updatedAlarmModel = + controller.updatedAlarmModel(); + await controller.updateAlarm(updatedAlarmModel); } + } catch (e) { + debugPrint(e.toString()); + } - await controller.checkOverlayPermissionAndNavigate(); + await controller.checkOverlayPermissionAndNavigate(); + }, + ), + ), + ), + appBar: AppBar( + backgroundColor: (controller.alarmRecord != null && + controller.mutexLock.value == true) + ? themeController.isLightMode.value + ? kLightPrimaryBackgroundColor + : kprimaryBackgroundColor + : themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + elevation: 0.0, + centerTitle: true, + iconTheme: Theme.of(context).iconTheme, + title: (controller.alarmRecord != null && + controller.mutexLock.value == true) + ? const Text('') + : Obx( + () => Text( + 'Rings in @timeToAlarm'.trParams( + { + 'timeToAlarm': controller.timeToAlarm.value.toString(), }, ), + style: Theme.of(context).textTheme.titleSmall, ), ), - appBar: AppBar( - backgroundColor: (controller.alarmRecord != null && - controller.mutexLock.value == true) - ? themeController.isLightMode.value - ? kLightPrimaryBackgroundColor - : kprimaryBackgroundColor - : themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - elevation: 0.0, - centerTitle: true, - iconTheme: Theme.of(context).iconTheme, - title: (controller.alarmRecord != null && - controller.mutexLock.value == true) - ? const Text('') - : Obx( - () => Text( - 'Rings in @timeToAlarm'.trParams( - { - 'timeToAlarm': - controller.timeToAlarm.value.toString(), - }, + ), + body: (controller.alarmRecord != null && + controller.mutexLock.value == true) + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Padding( + padding: const EdgeInsets.all(20.0), + child: Text( + 'Uh-oh!'.tr, + style: + Theme.of(context).textTheme.displayMedium!.copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - style: Theme.of(context).textTheme.titleSmall, ), - ), - ), - body: (controller.alarmRecord != null && - controller.mutexLock.value == true) - ? Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Padding( - padding: const EdgeInsets.all(20.0), - child: Text( - 'Uh-oh!'.tr, - style: Theme.of(context) - .textTheme - .displayMedium! - .copyWith( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - ), - SvgPicture.asset( - 'assets/images/locked.svg', - height: height * 0.24, - width: width * 0.5, + SvgPicture.asset( + 'assets/images/locked.svg', + height: height * 0.24, + width: width * 0.5, + ), + Padding( + padding: const EdgeInsets.all(20.0), + child: Text( + // 'This alarm is currently being edited!', + 'alarmEditing'.tr, + style: + Theme.of(context).textTheme.displaySmall!.copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Text( - // 'This alarm is currently being edited!', - 'alarmEditing'.tr, - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), + ), + TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(kprimaryColor), ), - TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(kprimaryColor), - ), - child: Text( - 'Go back'.tr, - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - color: themeController.isLightMode.value - ? kLightSecondaryTextColor - : ksecondaryTextColor, - ), - ), - onPressed: () { - Utils.hapticFeedback(); - Get.back(); - }, + child: Text( + 'Go back'.tr, + style: + Theme.of(context).textTheme.displaySmall!.copyWith( + color: themeController.isLightMode.value + ? kLightSecondaryTextColor + : ksecondaryTextColor, + ), ), - ], - ), - ) - : ListView( - children: [ - Container( - color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - height: height * 0.32, - width: width, - child: Obx( - () { - return InkWell( - onTap: () { - Utils.hapticFeedback(); - inputTimeController.changeDatePicker(); - }, - child: inputTimeController.isTimePicker.value - ? Obx( - () => Row( - mainAxisAlignment: - MainAxisAlignment.center, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - NumberPicker( - minValue: settingsController - .is24HrsEnabled.value - ? 0 - : 1, - maxValue: settingsController - .is24HrsEnabled.value - ? 23 - : 12, - value: controller.hours.value, - onChanged: (value) { - Utils.hapticFeedback(); - controller.hours.value = value; - controller.selectedTime.value = - DateTime( - controller - .selectedTime.value.year, - controller - .selectedTime.value.month, - controller.selectedTime.value.day, - inputTimeController - .convert24(value), - controller - .selectedTime.value.minute, - ); - inputTimeController - .inputHrsController.text = - controller.hours.value - .toString(); + onPressed: () { + Utils.hapticFeedback(); + Get.back(); + }, + ), + ], + ), + ) + : ListView( + children: [ + Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + height: height * 0.32, + width: width, + child: Obx( + () { + return InkWell( + onTap: () { + Utils.hapticFeedback(); + inputTimeController.changeDatePicker(); + }, + child: inputTimeController.isTimePicker.value + ? Obx( + () => Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + NumberPicker( + minValue: settingsController + .is24HrsEnabled.value + ? 0 + : 1, + maxValue: settingsController + .is24HrsEnabled.value + ? 23 + : 12, + value: controller.hours.value, + onChanged: (value) { + Utils.hapticFeedback(); + controller.hours.value = value; + controller.selectedTime.value = + DateTime( + controller.selectedTime.value.year, + controller.selectedTime.value.month, + controller.selectedTime.value.day, inputTimeController - .inputMinutesController - .text = - controller.minutes.value - .toString(); - inputTimeController.changePeriod( - controller.meridiemIndex.value == - 0 - ? 'AM' - : 'PM', - ); - }, - infiniteLoop: true, - itemWidth: width * 0.17, - zeroPad: true, - selectedTextStyle: Theme.of(context) + .convert24(value), + controller + .selectedTime.value.minute, + ); + inputTimeController + .inputHrsController.text = + controller.hours.value.toString(); + inputTimeController + .inputMinutesController.text = + controller.minutes.value + .toString(); + inputTimeController.changePeriod( + controller.meridiemIndex.value == 0 + ? 'AM' + : 'PM', + ); + }, + infiniteLoop: true, + itemWidth: width * 0.17, + zeroPad: true, + selectedTextStyle: Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: kprimaryColor, + ), + textStyle: Theme.of(context) + .textTheme + .displayMedium! + .copyWith( + fontSize: 20, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: width * 0.005, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + bottom: BorderSide( + width: width * 0.005, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + ), + ), + Padding( + padding: EdgeInsets.symmetric( + horizontal: width * 0.02, + ), + child: Text( + ':', + style: Theme.of(context) .textTheme .displayLarge! .copyWith( fontWeight: FontWeight.bold, - color: kprimaryColor, - ), - textStyle: Theme.of(context) - .textTheme - .displayMedium! - .copyWith( - fontSize: 20, - color: themeController - .isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - decoration: BoxDecoration( - border: Border( - top: BorderSide( - width: width * 0.005, - color: themeController - .isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - bottom: BorderSide( - width: width * 0.005, color: themeController .isLightMode.value ? kLightPrimaryDisabledTextColor : kprimaryDisabledTextColor, ), + ), + ), + NumberPicker( + minValue: 0, + maxValue: 59, + value: controller.minutes.value, + onChanged: (value) { + Utils.hapticFeedback(); + controller.minutes.value = value; + controller.selectedTime.value = + DateTime( + controller.selectedTime.value.year, + controller.selectedTime.value.month, + controller.selectedTime.value.day, + controller.selectedTime.value.hour, + controller.minutes.value, + ); + inputTimeController + .inputHrsController.text = + controller.hours.value.toString(); + inputTimeController + .inputMinutesController.text = + controller.minutes.value + .toString(); + inputTimeController.changePeriod( + controller.meridiemIndex.value == 0 + ? 'AM' + : 'PM', + ); + }, + infiniteLoop: true, + itemWidth: width * 0.17, + zeroPad: true, + selectedTextStyle: Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: kprimaryColor, + ), + textStyle: Theme.of(context) + .textTheme + .displayMedium! + .copyWith( + fontSize: 20, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: width * 0.005, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + bottom: BorderSide( + width: width * 0.005, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, ), ), ), - Padding( + ), + Visibility( + visible: settingsController + .is24HrsEnabled.value + ? false + : true, + child: Padding( padding: EdgeInsets.symmetric( horizontal: width * 0.02, ), @@ -477,13 +550,23 @@ class AddOrUpdateAlarmView extends GetView { ), ), ), - NumberPicker( + ), + Visibility( + visible: settingsController + .is24HrsEnabled.value + ? false + : true, + child: NumberPicker( minValue: 0, - maxValue: 59, - value: controller.minutes.value, + maxValue: 1, + value: controller.meridiemIndex.value, onChanged: (value) { Utils.hapticFeedback(); - controller.minutes.value = value; + value == 0 + ? controller + .meridiemIndex.value = 0 + : controller + .meridiemIndex.value = 1; controller.selectedTime.value = DateTime( controller @@ -491,8 +574,9 @@ class AddOrUpdateAlarmView extends GetView { controller .selectedTime.value.month, controller.selectedTime.value.day, - controller - .selectedTime.value.hour, + inputTimeController.convert24( + controller.hours.value, + ), controller.minutes.value, ); inputTimeController @@ -511,9 +595,12 @@ class AddOrUpdateAlarmView extends GetView { : 'PM', ); }, - infiniteLoop: true, + textMapper: (numberText) { + return controller + .meridiem[int.parse(numberText)] + .value; + }, itemWidth: width * 0.17, - zeroPad: true, selectedTextStyle: Theme.of(context) .textTheme .displayLarge! @@ -550,588 +637,485 @@ class AddOrUpdateAlarmView extends GetView { ), ), ), - Visibility( - visible: settingsController - .is24HrsEnabled.value - ? false - : true, - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: width * 0.02, - ), - child: Text( - ':', - style: Theme.of(context) - .textTheme - .displayLarge! - .copyWith( - fontWeight: FontWeight.bold, - color: themeController - .isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - ), + ), + ], + ), + ) + : Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: 80, + child: TextField( + onChanged: (_) { + inputTimeController.setTime(); + }, + decoration: const InputDecoration( + hintText: 'HH', + border: InputBorder.none, ), - Visibility( - visible: settingsController - .is24HrsEnabled.value - ? false - : true, - child: NumberPicker( - minValue: 0, - maxValue: 1, - value: - controller.meridiemIndex.value, - onChanged: (value) { - Utils.hapticFeedback(); - value == 0 - ? controller - .meridiemIndex.value = 0 - : controller - .meridiemIndex.value = 1; - controller.selectedTime.value = - DateTime( - controller - .selectedTime.value.year, - controller - .selectedTime.value.month, - controller - .selectedTime.value.day, - inputTimeController.convert24( - controller.hours.value), - controller.minutes.value, - ); - inputTimeController - .inputHrsController.text = - controller.hours.value - .toString(); - inputTimeController - .inputMinutesController - .text = - controller.minutes.value - .toString(); - inputTimeController.changePeriod( - controller.meridiemIndex - .value == - 0 - ? 'AM' - : 'PM', - ); - }, - textMapper: (numberText) { - return controller - .meridiem[ - int.parse(numberText)] - .value; - }, - itemWidth: width * 0.17, - selectedTextStyle: Theme.of(context) - .textTheme - .displayLarge! - .copyWith( - fontWeight: FontWeight.bold, - color: kprimaryColor, - ), - textStyle: Theme.of(context) - .textTheme - .displayMedium! - .copyWith( - fontSize: 20, - color: themeController - .isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - decoration: BoxDecoration( - border: Border( - top: BorderSide( - width: width * 0.005, - color: themeController - .isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - bottom: BorderSide( - width: width * 0.005, - color: themeController - .isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), + textAlign: TextAlign.center, + controller: inputTimeController + .inputHrsController, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp( + '[1,2,3,4,5,6,7,8,9,0]', ), ), - ), - ], - ), - ) - : Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - width: 80, - child: TextField( - onChanged: (_) { - inputTimeController.setTime(); - }, - decoration: const InputDecoration( - hintText: 'HH', - border: InputBorder.none, + LengthLimitingTextInputFormatter(2), + LimitRange( + 0, + settingsController + .is24HrsEnabled.value + ? 23 + : 12, ), - textAlign: TextAlign.center, - controller: inputTimeController - .inputHrsController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp( - '[1,2,3,4,5,6,7,8,9,0]', - ), - ), - LengthLimitingTextInputFormatter(2), - LimitRange( - 0, - settingsController - .is24HrsEnabled.value - ? 23 - : 12, - ), - ], - ), + ], ), - SizedBox( - width: 16, - child: Text( - ':', - textAlign: TextAlign.center, - style: Theme.of(context) - .textTheme - .titleMedium, - ), + ), + SizedBox( + width: 16, + child: Text( + ':', + textAlign: TextAlign.center, + style: Theme.of(context) + .textTheme + .titleMedium, ), - SizedBox( - width: 80, - child: TextField( - onChanged: (_) { - inputTimeController.setTime(); - }, - decoration: const InputDecoration( - hintText: 'MM', - border: InputBorder.none, - ), - textAlign: TextAlign.center, - controller: inputTimeController - .inputMinutesController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp( - '[1,2,3,4,5,6,7,8,9,0]', - ), - ), - LengthLimitingTextInputFormatter(2), - LimitRange(00, 59), - ], + ), + SizedBox( + width: 80, + child: TextField( + onChanged: (_) { + inputTimeController.setTime(); + }, + decoration: const InputDecoration( + hintText: 'MM', + border: InputBorder.none, ), + textAlign: TextAlign.center, + controller: inputTimeController + .inputMinutesController, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp( + '[1,2,3,4,5,6,7,8,9,0]', + ), + ), + LengthLimitingTextInputFormatter(2), + LimitRange(00, 59), + ], ), - const SizedBox( - width: 16, - ), - Visibility( - visible: !settingsController - .is24HrsEnabled.value, - child: DropdownButton( - underline: Container(), - value: inputTimeController.isAM.value - ? 'AM' - : 'PM', - dropdownColor: - themeController.isLightMode.value - ? kLightPrimaryBackgroundColor - : kprimaryBackgroundColor, - items: - ['AM', 'PM'].map((String period) { - return DropdownMenuItem( - value: period, - child: Text(period), - ); - }).toList(), - onChanged: (getPeriod) { - inputTimeController - .changePeriod(getPeriod!); + ), + const SizedBox( + width: 16, + ), + Visibility( + visible: !settingsController + .is24HrsEnabled.value, + child: DropdownButton( + underline: Container(), + value: inputTimeController.isAM.value + ? 'AM' + : 'PM', + dropdownColor: + themeController.isLightMode.value + ? kLightPrimaryBackgroundColor + : kprimaryBackgroundColor, + items: + ['AM', 'PM'].map((String period) { + return DropdownMenuItem( + value: period, + child: Text(period), + ); + }).toList(), + onChanged: (getPeriod) { + inputTimeController + .changePeriod(getPeriod!); - inputTimeController.setTime(); - }, - ), - ), - const SizedBox( - width: 12, + inputTimeController.setTime(); + }, ), - Visibility( - visible: inputTimeController - .isTimePicker.isFalse, - child: InkWell( - onTap: () { - Utils.hapticFeedback(); - inputTimeController - .confirmTimeInput(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(50.0), - border: Border.all( - color: kprimaryColor, - width: 1.0, - ), - ), - padding: EdgeInsets.all(5.0), - child: Icon( - Icons.done, + ), + const SizedBox( + width: 12, + ), + Visibility( + visible: inputTimeController + .isTimePicker.isFalse, + child: InkWell( + onTap: () { + Utils.hapticFeedback(); + inputTimeController + .confirmTimeInput(); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular(50.0), + border: Border.all( color: kprimaryColor, + width: 1.0, ), ), + padding: const EdgeInsets.all(5.0), + child: const Icon( + Icons.done, + color: kprimaryColor, + ), ), ), - ], - ), - ); - }, - ), - ), - RepeatTile( - controller: controller, - themeController: themeController, + ), + ], + ), + ); + }, ), - Container( + ), + RepeatTile( + controller: controller, + themeController: themeController, + ), + Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + child: Divider( color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - child: Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, ), - Obx( - () => (!controller.repeatDays - .every((element) => element == false)) - ? RepeatOnceTile( - controller: controller, - themeController: themeController, - ) - : const SizedBox(), - ), - Obx( - () => (!controller.repeatDays - .every((element) => element == false)) - ? Container( + ), + Obx( + () => (!controller.repeatDays + .every((element) => element == false)) + ? RepeatOnceTile( + controller: controller, + themeController: themeController, + ) + : const SizedBox(), + ), + Obx( + () => (!controller.repeatDays + .every((element) => element == false)) + ? Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + child: Divider( color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - child: Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ) - : const SizedBox(), - ), - SnoozeDurationTile( - controller: controller, - themeController: themeController, - ), - Container( - color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - child: Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - Obx( - () => (controller.repeatDays - .every((element) => element == false)) - ? DeleteAfterGoesOff( - controller: controller, - themeController: themeController, - ) - : const SizedBox(), - ), - LabelTile( - controller: controller, - themeController: themeController, - ), - Container( + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ) + : const SizedBox(), + ), + SnoozeDurationTile( + controller: controller, + themeController: themeController, + ), + Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + child: Divider( color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - child: Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - NoteTile( - controller: controller, - themeController: themeController, + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, ), - Container( + ), + Obx( + () => (controller.repeatDays + .every((element) => element == false)) + ? DeleteAfterGoesOff( + controller: controller, + themeController: themeController, + ) + : const SizedBox(), + ), + LabelTile( + controller: controller, + themeController: themeController, + ), + Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + child: Divider( color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - child: Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - ChooseRingtoneTile( - controller: controller, - themeController: themeController, - height: height, - width: width, + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, ), - Container( + ), + NoteTile( + controller: controller, + themeController: themeController, + ), + Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + child: Divider( color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - child: Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, ), - AscendingVolumeTile( - controller: controller, - themeController: themeController, - ), - Container( + ), + ChooseRingtoneTile( + controller: controller, + themeController: themeController, + height: height, + width: width, + ), + Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + child: Divider( color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - child: Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - QuoteTile( - controller: controller, - themeController: themeController, + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, ), - Container( + ), + AscendingVolumeTile( + controller: controller, + themeController: themeController, + ), + Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + child: Divider( color: themeController.isLightMode.value - ? kLightPrimaryBackgroundColor - : ksecondaryTextColor, - height: 10, - width: width, + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, ), - Container( - color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Padding( - padding: const EdgeInsets.only(top: 10.0), - child: Text( - 'Automatic Cancellation'.tr, - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith( - fontWeight: FontWeight.w500, - color: themeController.isLightMode.value - ? kLightPrimaryTextColor - .withOpacity(0.85) - : kprimaryTextColor.withOpacity(0.85), - ), - ), + ), + QuoteTile( + controller: controller, + themeController: themeController, + ), + Container( + color: themeController.isLightMode.value + ? kLightPrimaryBackgroundColor + : ksecondaryTextColor, + height: 10, + width: width, + ), + Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Padding( + padding: const EdgeInsets.only(top: 10.0), + child: Text( + 'Automatic Cancellation'.tr, + style: Theme.of(context) + .textTheme + .titleMedium! + .copyWith( + fontWeight: FontWeight.w500, + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + .withOpacity(0.85) + : kprimaryTextColor.withOpacity(0.85), + ), ), ), - ScreenActivityTile( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - WeatherTile( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - LocationTile( - controller: controller, - height: height, - width: width, - themeController: themeController, - ), - ], - ), - ), - Container( - color: themeController.isLightMode.value - ? kLightPrimaryBackgroundColor - : ksecondaryTextColor, - height: 10, - width: width, + ), + ScreenActivityTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + WeatherTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + LocationTile( + controller: controller, + height: height, + width: width, + themeController: themeController, + ), + ], ), - Container( - color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Padding( - padding: const EdgeInsets.only(top: 10.0), - child: Text( - 'Challenges'.tr, - style: Theme.of( - context, - ).textTheme.titleMedium!.copyWith( - fontWeight: FontWeight.w500, - color: themeController.isLightMode.value - ? kLightPrimaryTextColor - .withOpacity(0.85) - : kprimaryTextColor.withOpacity(0.85), - ), - ), + ), + Container( + color: themeController.isLightMode.value + ? kLightPrimaryBackgroundColor + : ksecondaryTextColor, + height: 10, + width: width, + ), + Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Padding( + padding: const EdgeInsets.only(top: 10.0), + child: Text( + 'Challenges'.tr, + style: Theme.of( + context, + ).textTheme.titleMedium!.copyWith( + fontWeight: FontWeight.w500, + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + .withOpacity(0.85) + : kprimaryTextColor.withOpacity(0.85), + ), ), ), - ShakeToDismiss( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - QrBarCode( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - MathsChallenge( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - PedometerChallenge( - controller: controller, - themeController: themeController, - ), - ], - ), - ), - Container( - color: themeController.isLightMode.value - ? kLightPrimaryBackgroundColor - : ksecondaryTextColor, - height: 10, - width: width, + ), + ShakeToDismiss( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + QrBarCode( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + MathsChallenge( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + PedometerChallenge( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + PhotoChallenge( + controller: controller, + themeController: themeController, + ), + ], ), - Container( - color: themeController.isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Padding( - padding: const EdgeInsets.only(top: 10.0), - child: Text( - 'Shared Alarm'.tr, - style: Theme.of( - context, - ).textTheme.titleMedium!.copyWith( - fontWeight: FontWeight.w500, - color: themeController.isLightMode.value - ? kLightPrimaryTextColor - .withOpacity(0.85) - : kprimaryTextColor.withOpacity(0.85), - ), - ), - ), - ), - SharedAlarm( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - AlarmIDTile( - controller: controller, - width: width, - themeController: themeController, - ), - Obx( - () => Container( - child: (controller.isSharedAlarmEnabled.value) - ? Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ) - : const SizedBox(), + ), + Container( + color: themeController.isLightMode.value + ? kLightPrimaryBackgroundColor + : ksecondaryTextColor, + height: 10, + width: width, + ), + Container( + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Padding( + padding: const EdgeInsets.only(top: 10.0), + child: Text( + 'Shared Alarm'.tr, + style: Theme.of( + context, + ).textTheme.titleMedium!.copyWith( + fontWeight: FontWeight.w500, + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + .withOpacity(0.85) + : kprimaryTextColor.withOpacity(0.85), + ), ), ), - AlarmOffset( - controller: controller, - themeController: themeController, - ), - Obx( - () => Container( - child: (controller.isSharedAlarmEnabled.value && - controller.alarmRecord != null) - ? Divider( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ) - : const SizedBox(), - ), + ), + SharedAlarm( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + AlarmIDTile( + controller: controller, + width: width, + themeController: themeController, + ), + Obx( + () => Container( + child: (controller.isSharedAlarmEnabled.value) + ? Divider( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ) + : const SizedBox(), ), - SharedUsers( - controller: controller, - themeController: themeController, + ), + AlarmOffset( + controller: controller, + themeController: themeController, + ), + Obx( + () => Container( + child: (controller.isSharedAlarmEnabled.value && + controller.alarmRecord != null) + ? Divider( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ) + : const SizedBox(), ), - ], - ), - ), - SizedBox( - height: height * 0.15, + ), + SharedUsers( + controller: controller, + themeController: themeController, + ), + ], ), - ], - ), - )); + ), + SizedBox( + height: height * 0.15, + ), + ], + ), + ), + ); } } diff --git a/lib/app/modules/addOrUpdateAlarm/views/choose_ringtone_tile.dart b/lib/app/modules/addOrUpdateAlarm/views/choose_ringtone_tile.dart index 9e07396f..51c19173 100644 --- a/lib/app/modules/addOrUpdateAlarm/views/choose_ringtone_tile.dart +++ b/lib/app/modules/addOrUpdateAlarm/views/choose_ringtone_tile.dart @@ -20,14 +20,14 @@ class ChooseRingtoneTile extends StatelessWidget { final double height; final double width; - void onTapPreview(String ringtonePath) async { + void onTapPreview(String ringtonePath) async { Utils.hapticFeedback(); - // Stop the currently playing audio before starting the preview for the new audio - await AudioUtils.stopPreviewCustomSound(); - - if (controller.isPlaying.value) { + // Stop the currently playing audio before starting the preview for the new + // audio + if (controller.isPlaying.value == true) { // If it was playing, reset the isPlaying state to false + await AudioUtils.stopPreviewCustomSound(); controller.toggleIsPlaying(); } else { await AudioUtils.previewCustomSound(ringtonePath); diff --git a/lib/app/modules/addOrUpdateAlarm/views/photo_challenge_tile.dart b/lib/app/modules/addOrUpdateAlarm/views/photo_challenge_tile.dart new file mode 100644 index 00000000..1c0e8f55 --- /dev/null +++ b/lib/app/modules/addOrUpdateAlarm/views/photo_challenge_tile.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart'; +import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; +import 'package:ultimate_alarm_clock/app/utils/constants.dart'; +import 'package:ultimate_alarm_clock/app/utils/utils.dart'; + +class PhotoChallenge extends StatelessWidget { + const PhotoChallenge({ + super.key, + required this.controller, + required this.themeController, + }); + + final AddOrUpdateAlarmController controller; + final ThemeController themeController; + + @override + Widget build(BuildContext context) { + return ListTile( + title: Row( + children: [ + FittedBox( + alignment: Alignment.centerLeft, + fit: BoxFit.scaleDown, + child: Text( + 'Photo'.tr, + style: TextStyle( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor, + ), + ), + ), + IconButton( + icon: Icon( + Icons.info_sharp, + size: 21, + color: themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.45) + : kprimaryTextColor.withOpacity(0.3), + ), + onPressed: () { + Utils.showModal( + context: context, + title: 'Photo'.tr, + // description: + // 'Scan the QR/Bar code on any object, like a book, and relocate it to a different room. To deactivate the alarm, simply rescan the same QR/Bar code.', + description: 'photoDescription', + iconData: Icons.camera_alt, + isLightMode: themeController.isLightMode.value, + ); + }, + ), + ], + ), + onTap: () async { + Utils.hapticFeedback(); + + await controller.requestPhotoPermission(context); + }, + trailing: InkWell( + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Obx( + () => Text( + controller.isPhotochallengeEnabled.value == true + ? 'Enabled'.tr + : 'Off'.tr, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: (controller.isPhotochallengeEnabled.value == false) + ? themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor + : themeController.isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor, + ), + ), + ), + Icon( + Icons.chevron_right, + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ], + ), + ), + ); + } +} diff --git a/lib/app/modules/addOrUpdateAlarm/views/qr_bar_code_tile.dart b/lib/app/modules/addOrUpdateAlarm/views/qr_bar_code_tile.dart index f3c4147c..cbffb856 100644 --- a/lib/app/modules/addOrUpdateAlarm/views/qr_bar_code_tile.dart +++ b/lib/app/modules/addOrUpdateAlarm/views/qr_bar_code_tile.dart @@ -46,7 +46,7 @@ class QrBarCode extends StatelessWidget { title: 'QR/Bar Code'.tr, // description: // 'Scan the QR/Bar code on any object, like a book, and relocate it to a different room. To deactivate the alarm, simply rescan the same QR/Bar code.', - description: 'qrDescription'.tr, + description: 'qrDescription', iconData: Icons.qr_code_scanner, isLightMode: themeController.isLightMode.value, ); @@ -56,6 +56,7 @@ class QrBarCode extends StatelessWidget { ), onTap: () async { Utils.hapticFeedback(); + await controller.requestQrPermission(context); }, trailing: InkWell( diff --git a/lib/app/modules/addOrUpdateAlarm/views/repeat_tile.dart b/lib/app/modules/addOrUpdateAlarm/views/repeat_tile.dart index e01cd947..86b7fb5c 100644 --- a/lib/app/modules/addOrUpdateAlarm/views/repeat_tile.dart +++ b/lib/app/modules/addOrUpdateAlarm/views/repeat_tile.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:get/get_connect/http/src/utils/utils.dart'; -import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/repeat_once_tile.dart'; import 'package:ultimate_alarm_clock/app/utils/constants.dart'; import 'package:ultimate_alarm_clock/app/utils/utils.dart'; @@ -38,10 +36,7 @@ class RepeatTile extends StatelessWidget { height: height * 0.45, child: Column( children: [ - buildDailyTile( - controller: controller, - themeController: themeController, - ), + buildDailyTile(), Container( color: themeController.isLightMode.value ? kLightSecondaryBackgroundColor @@ -52,10 +47,7 @@ class RepeatTile extends StatelessWidget { : kprimaryDisabledTextColor, ), ), - buildWeekdaysTile( - controller: controller, - themeController: themeController, - ), + buildWeekdaysTile(), Container( color: themeController.isLightMode.value ? kLightSecondaryBackgroundColor @@ -67,8 +59,6 @@ class RepeatTile extends StatelessWidget { ), ), buildCustomDaysTile( - controller: controller, - themeController: themeController, context: context, ), const SizedBox( @@ -168,12 +158,9 @@ class RepeatTile extends StatelessWidget { } } - ListTile buildDailyTile({ - required AddOrUpdateAlarmController controller, - required ThemeController themeController, - }) { + ListTile buildDailyTile() { return ListTile( - contentPadding: EdgeInsets.only(left: 10.0), + contentPadding: const EdgeInsets.only(left: 10.0), title: Obx( () => InkWell( onTap: () { @@ -186,7 +173,7 @@ class RepeatTile extends StatelessWidget { } }, child: Padding( - padding: EdgeInsets.all(8.0), // Adjust the padding as needed + padding: const EdgeInsets.all(8.0), // Adjust the padding as needed child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, @@ -261,13 +248,11 @@ class RepeatTile extends StatelessWidget { } ListTile buildCustomDaysTile({ - required AddOrUpdateAlarmController controller, - required ThemeController themeController, required BuildContext context, }) { List repeatDays = List.filled(7, false); return ListTile( - contentPadding: EdgeInsets.only(left: 10.0), + contentPadding: const EdgeInsets.only(left: 10.0), title: Obx( () => InkWell( onTap: () { @@ -362,7 +347,7 @@ class RepeatTile extends StatelessWidget { ); }, child: Padding( - padding: EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, @@ -393,12 +378,9 @@ class RepeatTile extends StatelessWidget { ); } - ListTile buildWeekdaysTile({ - required AddOrUpdateAlarmController controller, - required ThemeController themeController, - }) { + ListTile buildWeekdaysTile() { return ListTile( - contentPadding: EdgeInsets.only(left: 10.0), + contentPadding: const EdgeInsets.only(left: 10.0), title: Obx( () => InkWell( onTap: () { @@ -414,12 +396,12 @@ class RepeatTile extends StatelessWidget { } }, child: Padding( - padding: EdgeInsets.all(8.0), // Adjust the padding as needed + padding: const EdgeInsets.all(8.0), // Adjust the padding as needed child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( + const Text( 'Weekdays', ), Checkbox.adaptive( @@ -434,7 +416,8 @@ class RepeatTile extends StatelessWidget { onChanged: (value) { Utils.hapticFeedback(); controller.setIsWeekdaysSelected( - !controller.isWeekdaysSelected.value); + !controller.isWeekdaysSelected.value, + ); // Update repeatDays based on isWeekdaysSelected value for (int i = 0; i < controller.repeatDays.length; i++) { @@ -453,4 +436,4 @@ class RepeatTile extends StatelessWidget { ), ); } -} +} \ No newline at end of file diff --git a/lib/app/modules/addOrUpdateAlarm/views/weather_tile.dart b/lib/app/modules/addOrUpdateAlarm/views/weather_tile.dart index 54bd7625..3a41ddd4 100644 --- a/lib/app/modules/addOrUpdateAlarm/views/weather_tile.dart +++ b/lib/app/modules/addOrUpdateAlarm/views/weather_tile.dart @@ -460,71 +460,80 @@ class WeatherTile extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - SizedBox( - width: width * 0.4, - child: TextButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - kprimaryColor, + Expanded( + flex: 2, + child: SizedBox( + width: width * 0.4, + child: TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all( + kprimaryColor, + ), ), - ), - child: FittedBox( - fit: BoxFit.scaleDown, - alignment: Alignment.centerLeft, - child: Text( - 'Go to settings'.tr, - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - color: themeController - .isLightMode.value - ? kLightPrimaryTextColor - : ksecondaryTextColor, - ), + child: FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerLeft, + child: Text( + 'Go to settings'.tr, + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + color: themeController + .isLightMode.value + ? kLightPrimaryTextColor + : ksecondaryTextColor, + ), + ), ), + onPressed: () { + Utils.hapticFeedback(); + Get.back(); + Get.toNamed('/settings'); + }, ), - onPressed: () { - Utils.hapticFeedback(); - Get.back(); - Get.toNamed('/settings'); - }, ), ), SizedBox( width: width * 0.05, ), - SizedBox( - width: width * 0.3, - child: TextButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - themeController.isLightMode.value - ? kLightPrimaryTextColor - .withOpacity(0.5) - : kprimaryTextColor.withOpacity(0.5), + Expanded( + flex: 1, + child: SizedBox( + width: width * 0.3, + child: TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all( + themeController.isLightMode.value + ? kLightPrimaryTextColor + .withOpacity(0.5) + : kprimaryTextColor. + withOpacity(0.5), + ), ), - ), - child: FittedBox( - fit: BoxFit.scaleDown, - alignment: Alignment.centerLeft, - child: Text( - 'Cancel'.tr, - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - color: themeController - .isLightMode.value - ? kLightPrimaryTextColor - : kprimaryTextColor, - ), + child: FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerLeft, + child: Text( + 'Cancel'.tr, + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + color: themeController + .isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor, + ), + ), ), + onPressed: () { + Utils.hapticFeedback(); + Get.back(); + }, ), - onPressed: () { - Utils.hapticFeedback(); - Get.back(); - }, ), ), ], diff --git a/lib/app/modules/alarmChallenge/controllers/alarm_challenge_controller.dart b/lib/app/modules/alarmChallenge/controllers/alarm_challenge_controller.dart index ead36438..741f3256 100644 --- a/lib/app/modules/alarmChallenge/controllers/alarm_challenge_controller.dart +++ b/lib/app/modules/alarmChallenge/controllers/alarm_challenge_controller.dart @@ -1,7 +1,9 @@ import 'dart:async'; - +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; +import 'package:image_compare_2/image_compare_2.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:pedometer/pedometer.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -24,6 +26,10 @@ class AlarmChallengeController extends GetxController { final qrValue = ''.obs; final isQrOngoing = Status.initialized.obs; + final imageurl = ''.obs; + final isPhotoChallengeOngoing = Status.initialized.obs; + final imagesimilarity = 0.0.obs; + final isMathsOngoing = Status.initialized.obs; final RxInt numMathsQuestions = 0.obs; @@ -86,6 +92,24 @@ class AlarmChallengeController extends GetxController { } } + Future compareImage(String imagePath1, String imagePath2) async { + // Read the images + + // Load images + final image1 = File(imagePath1); + final image2 = File(imagePath2); + + final similarity = await compareImages( + src1: image1, + src2: image2, + algorithm: IntersectionHistogram(), + ); + + final result = similarity; + // Get.log('${result}'); + return result; + } + @override void onInit() async { super.onInit(); @@ -137,6 +161,17 @@ class AlarmChallengeController extends GetxController { }); } + if (alarmRecord.isPhotochallengeEnabled) { + imagesimilarity.listen((value) async { + if (value <= 0.36) { + isPhotoChallengeOngoing.value = Status.completed; + alarmRecord.isPhotochallengeEnabled = false; + Get.back(); + isChallengesComplete(); + } + }); + } + if (alarmRecord.isMathsEnabled) { newMathsQuestion(); diff --git a/lib/app/modules/alarmChallenge/views/alarm_challenge_view.dart b/lib/app/modules/alarmChallenge/views/alarm_challenge_view.dart index 106f6362..b6ad4e7d 100644 --- a/lib/app/modules/alarmChallenge/views/alarm_challenge_view.dart +++ b/lib/app/modules/alarmChallenge/views/alarm_challenge_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:ultimate_alarm_clock/app/modules/alarmChallenge/views/maths_challenge_view.dart'; import 'package:ultimate_alarm_clock/app/modules/alarmChallenge/views/pedometer_challenge_view.dart'; +import 'package:ultimate_alarm_clock/app/modules/alarmChallenge/views/photo_challengeview.dart'; import 'package:ultimate_alarm_clock/app/modules/alarmChallenge/views/qr_challenge_view.dart'; import 'package:ultimate_alarm_clock/app/modules/alarmChallenge/views/shake_challenge_view.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; @@ -13,7 +14,7 @@ import '../controllers/alarm_challenge_controller.dart'; class AlarmChallengeView extends GetView { AlarmChallengeView({Key? key}) : super(key: key); - ThemeController themeController = Get.find(); + final ThemeController themeController = Get.find(); @override Widget build(BuildContext context) { @@ -325,6 +326,74 @@ class AlarmChallengeView extends GetView { height: 20, width: 0, ), + if (controller.alarmRecord.isPhotochallengeEnabled) + InkWell( + onTap: () { + Utils.hapticFeedback(); + if (controller.isPhotoChallengeOngoing.value != + Status.completed && + controller + .alarmRecord.isPhotochallengeEnabled) { + Get.to(() => PhotoChallengeView()); + } + }, + child: Container( + width: width * 0.91, + height: height * 0.1, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(18), + ), + color: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceAround, + children: [ + Icon( + Icons.qr_code_scanner, + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + .withOpacity(0.8) + : kprimaryTextColor.withOpacity(0.8), + size: 28, + ), + Text( + 'Photo Challenge', + style: Theme.of(context) + .textTheme + .bodyLarge! + .copyWith( + color: themeController + .isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor, + ), + ), + Obx( + () => Icon( + controller.isPhotoChallengeOngoing + .value == + Status.completed + ? Icons.done + : Icons.arrow_forward_ios_sharp, + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + .withOpacity(0.4) + : kprimaryTextColor + .withOpacity(0.2), + ), + ), + ], + ), + ), + ), + const SizedBox( + height: 20, + width: 0, + ), ], ), ), diff --git a/lib/app/modules/alarmChallenge/views/maths_challenge_view.dart b/lib/app/modules/alarmChallenge/views/maths_challenge_view.dart index bbf9ab06..6b6cb858 100644 --- a/lib/app/modules/alarmChallenge/views/maths_challenge_view.dart +++ b/lib/app/modules/alarmChallenge/views/maths_challenge_view.dart @@ -8,7 +8,7 @@ import 'package:ultimate_alarm_clock/app/utils/utils.dart'; class MathsChallengeView extends GetView { MathsChallengeView({Key? key}) : super(key: key); - ThemeController themeController = Get.find(); + final ThemeController themeController = Get.find(); @override Widget build(BuildContext context) { @@ -44,13 +44,19 @@ class MathsChallengeView extends GetView { ? Column( children: [ Padding( - padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 30.0), + padding: const EdgeInsets.fromLTRB( + 16.0, 16.0, 16.0, 30.0), child: Obx( - () => Text( - 'Question @noMathQ'.trParams({ - 'noMathQ' : controller.numMathsQuestions.value.toString(), - }), - style: Theme.of(context).textTheme.displayMedium?.copyWith( + () => Text( + 'Question @noMathQ'.trParams({ + 'noMathQ': controller + .numMathsQuestions.value + .toString(), + }), + style: Theme.of(context) + .textTheme + .displayMedium + ?.copyWith( letterSpacing: 1.5, ), ), @@ -203,6 +209,7 @@ class MathsChallengeView extends GetView { return ElevatedButton( onPressed: () { Utils.hapticFeedback(); + if (controller.mathsAnswer.toString() == controller.displayValue.value) { controller.numMathsQuestions.value -= 1; diff --git a/lib/app/modules/alarmChallenge/views/pedometer_challenge_view.dart b/lib/app/modules/alarmChallenge/views/pedometer_challenge_view.dart index 7a5c35ef..e4678ce7 100644 --- a/lib/app/modules/alarmChallenge/views/pedometer_challenge_view.dart +++ b/lib/app/modules/alarmChallenge/views/pedometer_challenge_view.dart @@ -8,7 +8,7 @@ import 'package:ultimate_alarm_clock/app/utils/utils.dart'; class PedometerChallengeView extends GetView { PedometerChallengeView({Key? key}) : super(key: key); - ThemeController themeController = Get.find(); + final ThemeController themeController = Get.find(); @override Widget build(BuildContext context) { diff --git a/lib/app/modules/alarmChallenge/views/photo_challengeview.dart b/lib/app/modules/alarmChallenge/views/photo_challengeview.dart new file mode 100644 index 00000000..25efd794 --- /dev/null +++ b/lib/app/modules/alarmChallenge/views/photo_challengeview.dart @@ -0,0 +1,276 @@ +// ignore_for_file: lines_longer_than_80_chars + +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; +import 'package:ultimate_alarm_clock/app/utils/constants.dart'; +import 'package:ultimate_alarm_clock/app/utils/utils.dart'; + +import '../controllers/alarm_challenge_controller.dart'; + +class PhotoChallengeView extends GetView { + PhotoChallengeView({Key? key}) : super(key: key); + + final ThemeController themeController = Get.find(); + + @override + Widget build(BuildContext context) { + // ignore: unused_local_variable + var width = Get.width; + var height = Get.height; + + return Scaffold( + appBar: AppBar( + centerTitle: true, + iconTheme: Theme.of(context).iconTheme, + ), + body: GestureDetector( + onTap: () { + Utils.hapticFeedback(); + controller.restartTimer(); + }, + child: Column( + children: [ + Obx( + () => LinearProgressIndicator( + minHeight: 2, + value: controller.progress.value, + backgroundColor: Colors.grey, + valueColor: const AlwaysStoppedAnimation(kprimaryColor), + ), + ), + Expanded( + child: Center( + child: SingleChildScrollView( + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 25.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Match the Photo', + style: Theme.of(context) + .textTheme + .displayMedium! + .copyWith( + fontWeight: FontWeight.w500, + color: themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.7) + : kprimaryTextColor.withOpacity(0.7), + ), + ), + SizedBox( + height: height * 0.08, + ), + Obx( + () => Column( + children: [ + (controller.isPhotoChallengeOngoing.value == + Status.initialized) + ? Column( + children: [ + Padding( + padding: const EdgeInsets.only( + bottom: 15.0, + ), + child: File( + controller.alarmRecord.imageurl, + ).existsSync() + // Check if file exists before trying to display + ? Image.file( + File( + controller + .alarmRecord.imageurl, + ), + fit: BoxFit.contain, + height: MediaQuery.of( + Get.context!, + ).size.height * + 0.36, + width: MediaQuery.of( + Get.context!, + ).size.width * + 0.81, + ) + : const CircularProgressIndicator(), + ), + TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all( + kprimaryColor, + ), + ), + child: Text( + 'Take Photo'.tr, + style: Theme.of(Get.context!) + .textTheme + .displaySmall! + .copyWith( + color: themeController + .isLightMode.value + ? kLightPrimaryTextColor + : ksecondaryTextColor, + ), + ), + onPressed: () async { + PermissionStatus cameraStatus = + await Permission + .camera.status; + if (cameraStatus.isGranted) { + final pickedFile = + await ImagePicker() + .pickImage( + source: ImageSource.camera, + ); + if (pickedFile != null) { + final imageFile = + File(pickedFile.path); + controller.imageurl.value = + imageFile.path; + + controller.imagesimilarity + .value = + await controller + .compareImage( + controller + .alarmRecord.imageurl, + controller.imageurl.value, + ); + Get.log( + '${controller.imagesimilarity.value}', + ); + if (controller.imagesimilarity + .value <= + 0.36) { + controller + .isPhotoChallengeOngoing + .value = Status.completed; + } else { + controller + .isPhotoChallengeOngoing + .value = Status.ongoing; + } + + // await imageFile.delete(); + } else {} + // Process the image as needed + } else {} + }, + ), + ], + ) + : SizedBox( + height: 300, + width: 300, + child: Center( + child: (controller + .imagesimilarity.value <= + 0.36) + ? Icon( + Icons.done, + size: height * 0.2, + color: themeController + .isLightMode.value + ? kLightPrimaryTextColor + .withOpacity(0.7) + : kprimaryTextColor + .withOpacity(0.7), + ) + : Column( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Icon( + Icons.close, + size: height * 0.2, + color: themeController + .isLightMode.value + ? kLightPrimaryTextColor + .withOpacity(0.7) + : kprimaryTextColor + .withOpacity( + 0.7, + ), + ), + Text( + 'Wrong Photo Captured', + style: Theme.of( + context, + ) + .textTheme + .bodyMedium! + .copyWith( + fontWeight: + FontWeight.w500, + color: themeController + .isLightMode + .value + ? kLightPrimaryTextColor + .withOpacity( + 0.7, + ) + : kprimaryTextColor + .withOpacity( + 0.7, + ), + ), + ), + TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty + .all( + kprimaryColor, + ), + ), + child: Text( + 'Retake', + style: Theme.of( + context, + ) + .textTheme + .displaySmall! + .copyWith( + color: themeController + .isLightMode + .value + ? kLightSecondaryTextColor + : ksecondaryTextColor, + ), + ), + onPressed: () async { + Utils.hapticFeedback(); + + controller + .isPhotoChallengeOngoing + .value = + Status.initialized; + }, + ), + ], + ), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/app/modules/alarmChallenge/views/qr_challenge_view.dart b/lib/app/modules/alarmChallenge/views/qr_challenge_view.dart index fd73a452..98cdb5d5 100644 --- a/lib/app/modules/alarmChallenge/views/qr_challenge_view.dart +++ b/lib/app/modules/alarmChallenge/views/qr_challenge_view.dart @@ -12,7 +12,7 @@ import '../controllers/alarm_challenge_controller.dart'; class QRChallengeView extends GetView { QRChallengeView({Key? key}) : super(key: key); - ThemeController themeController = Get.find(); + final ThemeController themeController = Get.find(); @override Widget build(BuildContext context) { diff --git a/lib/app/modules/alarmChallenge/views/shake_challenge_view.dart b/lib/app/modules/alarmChallenge/views/shake_challenge_view.dart index d4f6778d..0dcc3cf3 100644 --- a/lib/app/modules/alarmChallenge/views/shake_challenge_view.dart +++ b/lib/app/modules/alarmChallenge/views/shake_challenge_view.dart @@ -10,7 +10,7 @@ import '../controllers/alarm_challenge_controller.dart'; class ShakeChallengeView extends GetView { ShakeChallengeView({Key? key}) : super(key: key); - ThemeController themeController = Get.find(); + final ThemeController themeController = Get.find(); @override Widget build(BuildContext context) { diff --git a/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart b/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart index c556fe5e..23c96171 100644 --- a/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart +++ b/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart @@ -66,6 +66,10 @@ class AlarmControlController extends GetxController { return latestAlarm; } + void addMinutes(int incrementMinutes) { + minutes.value += incrementMinutes; + } + void startSnooze() async { Vibration.cancel(); vibrationTimer!.cancel(); diff --git a/lib/app/modules/alarmRing/views/alarm_ring_view.dart b/lib/app/modules/alarmRing/views/alarm_ring_view.dart index d547cf6d..e37b76ea 100644 --- a/lib/app/modules/alarmRing/views/alarm_ring_view.dart +++ b/lib/app/modules/alarmRing/views/alarm_ring_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; @@ -10,7 +11,33 @@ import '../controllers/alarm_ring_controller.dart'; class AlarmControlView extends GetView { AlarmControlView({Key? key}) : super(key: key); - ThemeController themeController = Get.find(); + final ThemeController themeController = Get.find(); + + TextButton getAddSnoozeButtons( + BuildContext context, int snoozeMinutes, String title) { + return TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + ), + ), + child: Text( + title.tr, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor, + fontWeight: FontWeight.w600, + ), + ), + onPressed: () { + Utils.hapticFeedback(); + controller.addMinutes(snoozeMinutes); + }, + ); + } @override Widget build(BuildContext context) { @@ -79,7 +106,7 @@ class AlarmControlView extends GetView { Get.offNamed( '/bottom-navigation-bar', arguments: controller.currentlyRingingAlarm - .value.showMotivationalQuote, + .value, ); } }, @@ -152,6 +179,23 @@ class AlarmControlView extends GetView { .displayLarge! .copyWith(fontSize: 50), ), + const SizedBox( + height: 20, + width: 0, + ), + Obx( + () => Visibility( + visible: controller.isSnoozing.value, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + getAddSnoozeButtons(context, 1, '+1 min'), + getAddSnoozeButtons(context, 2, '+2 min'), + getAddSnoozeButtons(context, 5, '+5 min'), + ], + ), + ), + ), ], ), ), @@ -193,13 +237,15 @@ class AlarmControlView extends GetView { ), child: Text( 'Snooze'.tr, - style: - Theme.of(context).textTheme.bodyMedium!.copyWith( - color: themeController.isLightMode.value - ? kLightPrimaryTextColor - : kprimaryTextColor, - fontWeight: FontWeight.w600, - ), + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor, + fontWeight: FontWeight.w600, + ), ), onPressed: () { Utils.hapticFeedback(); diff --git a/lib/app/modules/bottomNavigationBar/bindings/bottom_navigation_bar_binding.dart b/lib/app/modules/bottomNavigationBar/bindings/bottom_navigation_bar_binding.dart index de7180ef..449db2f4 100644 --- a/lib/app/modules/bottomNavigationBar/bindings/bottom_navigation_bar_binding.dart +++ b/lib/app/modules/bottomNavigationBar/bindings/bottom_navigation_bar_binding.dart @@ -1,4 +1,5 @@ import 'package:get/get.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/bottomNavigationBar/controllers/bottom_navigation_bar_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/home/controllers/home_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/settings_controller.dart'; @@ -19,5 +20,6 @@ class BottomNavigationBarBinding extends Bindings { ); Get.lazyPut(() => SettingsController(), fenix: true); Get.lazyPut(() => HomeController()); + Get.lazyPut(() => AddOrUpdateAlarmController()); } } diff --git a/lib/app/modules/bottomNavigationBar/controllers/bottom_navigation_bar_controller.dart b/lib/app/modules/bottomNavigationBar/controllers/bottom_navigation_bar_controller.dart index a17c8ac5..4a8815db 100644 --- a/lib/app/modules/bottomNavigationBar/controllers/bottom_navigation_bar_controller.dart +++ b/lib/app/modules/bottomNavigationBar/controllers/bottom_navigation_bar_controller.dart @@ -10,6 +10,7 @@ class BottomNavigationBarController extends GetxController with WidgetsBindingObserver { RxInt activeTabIndex = 0.obs; RxBool isTimerRunning = false.obs; + RxBool hasloaded = false.obs; final _secureStorageProvider = SecureStorageProvider(); @@ -25,7 +26,7 @@ class BottomNavigationBarController extends GetxController void onInit() { super.onInit(); WidgetsBinding.instance.addObserver(this); - _loadSavedState(); + loadSavedState(); } @override @@ -34,18 +35,10 @@ class BottomNavigationBarController extends GetxController super.onClose(); } - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - super.didChangeAppLifecycleState(state); - - if (state == AppLifecycleState.inactive || - state == AppLifecycleState.paused) { - _saveState(); - } - } - - void _loadSavedState() async { - activeTabIndex.value = await _secureStorageProvider.readTabIndex(); + Future loadSavedState() async { + int value = await _secureStorageProvider.readTabIndex(); + activeTabIndex.value = value; + hasloaded.value = true; } void _saveState() async { @@ -56,6 +49,7 @@ class BottomNavigationBarController extends GetxController void changeTab(int index) { activeTabIndex.value = index; + _saveState(); if (index == 0 && (timerController.isTimerRunning.value || isTimerRunning.value)) { diff --git a/lib/app/modules/bottomNavigationBar/views/bottom_navigation_bar_view.dart b/lib/app/modules/bottomNavigationBar/views/bottom_navigation_bar_view.dart index 9e863b9d..63fda0b7 100644 --- a/lib/app/modules/bottomNavigationBar/views/bottom_navigation_bar_view.dart +++ b/lib/app/modules/bottomNavigationBar/views/bottom_navigation_bar_view.dart @@ -1,48 +1,79 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:ultimate_alarm_clock/app/modules/bottomNavigationBar/controllers/bottom_navigation_bar_controller.dart'; +import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; +import 'package:ultimate_alarm_clock/app/utils/constants.dart'; import 'package:ultimate_alarm_clock/app/utils/utils.dart'; class BottomNavigationBarView extends GetView { - final PageController pageController = PageController(); + PageController pageController = PageController(); + final ThemeController themeController = Get.find(); + BottomNavigationBarView({super.key}); @override Widget build(BuildContext context) { return Scaffold( - body: PageView( - controller: pageController, - children: controller.pages, - onPageChanged: (index) { - controller.changeTab(index); - }, - ), + body: Obx(() { + return FutureBuilder( + future: controller.loadSavedState(), + builder: (context, snapshot) { + if (controller.hasloaded.value != false) { + pageController = + PageController(initialPage: controller.activeTabIndex.value); + return PageView( + controller: pageController, + children: controller.pages, + onPageChanged: (index) { + controller.changeTab(index); + }, + ); + } else { + return const Center( + child: CircularProgressIndicator.adaptive( + backgroundColor: Colors.transparent, + valueColor: AlwaysStoppedAnimation( + kprimaryColor, + ), + ), + ); + } + }, + ); + }), bottomNavigationBar: Obx( () => BottomNavigationBar( useLegacyColorScheme: false, items: [ BottomNavigationBarItem( - icon: Icon(Icons.alarm), + icon: const Icon(Icons.alarm), label: 'Alarm'.tr, ), BottomNavigationBarItem( - icon: Icon(Icons.timer_outlined), + icon: const Icon(Icons.timer_outlined), label: 'StopWatch'.tr, ), BottomNavigationBarItem( - icon: Icon(Icons.timelapse_outlined), + icon: const Icon(Icons.timelapse_outlined), label: 'Timer'.tr, ), ], onTap: (index) { Utils.hapticFeedback(); controller.changeTab(index); - pageController.animateToPage(index, - duration: Duration(milliseconds: 300), curve: Curves.easeInOut); + pageController.jumpToPage( + index, + ); }, currentIndex: controller.activeTabIndex.value, + selectedLabelStyle: TextStyle( + color: kprimaryColor, + fontSize: 14, + decorationColor: + themeController.isLightMode.value ? Colors.black : Colors.white, + decorationThickness: 0.8, + ), ), ), ); } } - diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 108eb277..48539b48 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -1,6 +1,8 @@ import 'dart:async'; +import 'dart:io'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:rxdart/rxdart.dart' as rx; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; @@ -25,6 +27,7 @@ class Pair { } class HomeController extends GetxController { + MethodChannel alarmChannel = const MethodChannel('ulticlock'); Stream? firestoreStreamAlarms; Stream? sharedAlarmsStream; @@ -33,6 +36,7 @@ class HomeController extends GetxController { List latestFirestoreAlarms = []; List latestIsarAlarms = []; List latestSharedAlarms = []; + Map deletedAlarmsMap = {}; final alarmTime = 'No upcoming alarms!'.obs; bool refreshTimer = false; bool isEmpty = true; @@ -61,6 +65,9 @@ class HomeController extends GetxController { Set> selectedAlarmSet = {}; + final RxInt duration = 3.obs; + final RxDouble selecteddurationDouble = 0.0.obs; + ThemeController themeController = Get.find(); loginWithGoogle() async { @@ -229,7 +236,7 @@ class HomeController extends GetxController { }); if (Get.arguments != null) { - bool showMotivationalQuote = Get.arguments; + bool showMotivationalQuote = Get.arguments.showMotivationalQuote; if (showMotivationalQuote) { Quote quote = Utils.getRandomQuote(); @@ -391,21 +398,37 @@ class HomeController extends GetxController { try { await alarmChannel .invokeMethod('scheduleAlarm', {'milliSeconds': intervaltoAlarm}); - print("Scheduled..."); + debugPrint('Scheduled...'); } on PlatformException catch (e) { - print("Failed to schedule alarm: ${e.message}"); + debugPrint('Failed to schedule alarm: ${e.message}'); } } } } @override - void onClose() { - super.onClose(); - + void onClose() async { + //Deleting file cache stored in temporary directory + for (var filepath in deletedAlarmsMap.values) { + await deleteFileIfExists(filepath); + } + deletedAlarmsMap.clear(); if (delayToSchedule != null) { delayToSchedule!.cancel(); } + + super.onClose(); + } + + Future deleteFileIfExists(String filePath) async { + File file = File(filePath); + + if (await file.exists()) { + await file.delete(); + debugPrint('File deleted successfully.'); + } else { + debugPrint('File does not exist.'); + } } // Add all alarms to seleted alarm set @@ -534,9 +557,9 @@ class HomeController extends GetxController { } Get.snackbar( - 'Alarm deleted'.tr, - 'The alarm has been deleted'.tr, - duration: const Duration(seconds: 4), + 'Alarm deleted', + 'The alarm has been deleted.', + duration: Duration(seconds: duration.toInt()), snackPosition: SnackPosition.BOTTOM, margin: const EdgeInsets.symmetric( horizontal: 10, diff --git a/lib/app/modules/home/views/home_view.dart b/lib/app/modules/home/views/home_view.dart index e0878d83..66c245ce 100644 --- a/lib/app/modules/home/views/home_view.dart +++ b/lib/app/modules/home/views/home_view.dart @@ -1,16 +1,20 @@ // ignore_for_file: lines_longer_than_80_chars +// import 'dart:ffi'; +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:ultimate_alarm_clock/app/data/models/alarm_model.dart'; import 'package:ultimate_alarm_clock/app/data/providers/firestore_provider.dart'; import 'package:ultimate_alarm_clock/app/data/providers/isar_provider.dart'; import 'package:ultimate_alarm_clock/app/modules/home/views/toggle_button.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/settings_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; -import 'package:ultimate_alarm_clock/app/routes/app_pages.dart'; +// import 'package:ultimate_alarm_clock/app/routes/app_pages.dart'; import 'package:ultimate_alarm_clock/app/utils/audio_utils.dart'; import 'package:ultimate_alarm_clock/app/utils/constants.dart'; import 'package:ultimate_alarm_clock/app/utils/end_drawer.dart'; @@ -283,8 +287,8 @@ class HomeView extends GetView { : ExpandableFab( initialOpen: false, key: controller.floatingButtonKeyLoggedOut, - child: Icon(Icons.add), - children: [], + child: const Icon(Icons.add), + children: const [], onOpen: () { controller.floatingButtonKeyLoggedOut.currentState! .toggle(); @@ -511,7 +515,7 @@ class HomeView extends GetView { ), Container( padding: EdgeInsets.symmetric( - horizontal: 4 * + horizontal: 2 * controller .scalingFactor.value, ), @@ -581,7 +585,7 @@ class HomeView extends GetView { ), ); }), - Spacer(), + const Spacer(), Row( children: [ // All alarm select button @@ -637,10 +641,12 @@ class HomeView extends GetView { .value ? kLightPrimaryTextColor .withOpacity( - 0.75) + 0.75, + ) : kprimaryTextColor .withOpacity( - 0.75), + 0.75, + ), iconSize: 27 * controller .scalingFactor @@ -651,7 +657,7 @@ class HomeView extends GetView { ), ], ), - ) + ), ], ), ), @@ -667,343 +673,336 @@ class HomeView extends GetView { ), ], - body: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Expanded( - child: GlowingOverscrollIndicator( - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - axisDirection: AxisDirection.down, - child: Obx(() { - return FutureBuilder( - future: controller.isUserSignedIn.value - ? controller.initStream(controller.userModel.value) - : controller.initStream(controller.userModel.value), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - final Stream streamAlarms = snapshot.data; + body: RefreshIndicator( + onRefresh: () async { + refresh(context); + }, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Expanded( + child: GlowingOverscrollIndicator( + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + axisDirection: AxisDirection.down, + child: Obx(() { + return FutureBuilder( + future: controller.isUserSignedIn.value + ? controller + .initStream(controller.userModel.value) + : controller + .initStream(controller.userModel.value), + builder: (context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + final Stream streamAlarms = snapshot.data; - return StreamBuilder( - stream: streamAlarms, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return const Center( - child: CircularProgressIndicator.adaptive( - backgroundColor: Colors.transparent, - valueColor: AlwaysStoppedAnimation( - kprimaryColor, - ), - ), - ); - } else { - List alarms = snapshot.data; - - alarms = alarms - .where((alarm) => !alarm.isTimer) - .toList(); - controller.refreshTimer = true; - controller.refreshUpcomingAlarms(); - if (alarms.isEmpty) { - return Center( - child: Column( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - children: [ - SvgPicture.asset( - 'assets/images/empty.svg', - height: height * 0.3, - width: width * 0.8, - ), - Text( - 'Add an alarm to get started!'.tr, - textWidthBasis: - TextWidthBasis.longestLine, - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - color: themeController - .isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - ], + return StreamBuilder( + stream: streamAlarms, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return const Center( + child: CircularProgressIndicator.adaptive( + backgroundColor: Colors.transparent, + valueColor: AlwaysStoppedAnimation( + kprimaryColor, + ), ), ); - } - return ListView.separated( - separatorBuilder: (context, _) { - return SizedBox( - height: height * 0.02, + } else { + List alarms = snapshot.data; + + alarms = alarms + .where((alarm) => !alarm.isTimer) + .toList(); + controller.refreshTimer = true; + controller.refreshUpcomingAlarms(); + if (alarms.isEmpty) { + return Center( + child: Column( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + SvgPicture.asset( + 'assets/images/empty.svg', + height: height * 0.3, + width: width * 0.8, + ), + Text( + 'Add an alarm to get started!'.tr, + textWidthBasis: + TextWidthBasis.longestLine, + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + ], + ), ); - }, - itemCount: alarms.length + 1, - itemBuilder: (context, index) { - // Spacing after last card - if (index == alarms.length) { + } + return ListView.separated( + separatorBuilder: (context, _) { return SizedBox( - height: height * 0.1, + height: height * 0.02, ); - } - final AlarmModel alarm = alarms[index]; - - final repeatDays = - Utils.getRepeatDays(alarm.days); - // Main card - return Dismissible( - direction: DismissDirection.startToEnd, - onDismissed: (direction) async { - await controller.swipeToDeleteAlarm( - controller.userModel.value, - alarm); - }, - key: ValueKey(alarms[index]), - background: Container( - color: Colors - .red, // Set the background color to red - padding: EdgeInsets.symmetric( - horizontal: 20), - alignment: Alignment.center, - child: Icon( - Icons.delete, - color: Colors.white, - ), - ), - child: Obx( - () => GestureDetector( - onTap: () { - Utils.hapticFeedback(); - - // If multiple select mode is not on, then only you can update the alarm - if (!controller - .inMultipleSelectMode.value) { - Get.toNamed( - '/add-update-alarm', - arguments: alarm, + }, + itemCount: alarms.length + 1, + itemBuilder: (context, index) { + // Spacing after last card + if (index == alarms.length) { + return SizedBox( + height: height * 0.1, + ); + } + final AlarmModel alarm = alarms[index]; + final repeatDays = + Utils.getRepeatDays(alarm.days); + // Main card + return Dismissible( + onDismissed: (direction) async { + // pop up confirmation to delete on swipe + bool userConfirmed = + await showDeleteAlarmConfirmationPopupOnSwipe( + context, + ); + if (userConfirmed) { + if (alarm.isSharedAlarmEnabled == + true) { + await FirestoreDb.deleteAlarm( + controller.userModel.value, + alarm.firestoreId!, + ); + } else { + await IsarDb.deleteAlarm( + alarm.isarId, ); } - }, - onLongPress: () { - // Entering the multiple select mode - controller.inMultipleSelectMode - .value = true; - controller.isAnyAlarmHolded - .value = true; - - // Assigning the alarm list pairs to list of alarms and list of isSelected all equal to false initially - controller.alarmListPairs = Pair( - alarms, - List.generate( - alarms.length, - (index) => false.obs, - ), + } else { + // do not delete on dismiss + Get.offNamedUntil( + '/bottom-navigation-bar', + (route) => + route.settings.name == + '/splash-screen', ); + } + }, + key: ValueKey(alarms[index]), + background: Container( + color: Colors + .red, // Set the background color to red + padding: EdgeInsets.symmetric( + horizontal: 20, + ), + alignment: Alignment.center, + child: Icon( + Icons.delete, + color: Colors.white, + ), + ), + child: Obx( + () => GestureDetector( + onTap: () { + Utils.hapticFeedback(); - Utils.hapticFeedback(); - }, - onLongPressEnd: (details) { - controller.isAnyAlarmHolded - .value = false; - }, - child: AnimatedContainer( - duration: const Duration( - milliseconds: 600, - ), - curve: Curves.easeInOut, - margin: EdgeInsets.all( - controller - .isAnyAlarmHolded.value - ? 10 - : 0, - ), - child: Center( - child: Padding( - padding: const EdgeInsets - .symmetric( - horizontal: 10.0, + // If multiple select mode is not on, then only you can update the alarm + if (!controller + .inMultipleSelectMode + .value) { + Get.toNamed( + '/add-update-alarm', + arguments: alarm, + ); + } + }, + onLongPress: () { + // Entering the multiple select mode + controller.inMultipleSelectMode + .value = true; + controller.isAnyAlarmHolded + .value = true; + + // Assigning the alarm list pairs to list of alarms and list of isSelected all equal to false initially + controller.alarmListPairs = + Pair( + alarms, + List.generate( + alarms.length, + (index) => false.obs, ), - child: Card( - color: themeController - .isLightMode.value - ? kLightSecondaryBackgroundColor - : ksecondaryBackgroundColor, - shape: - RoundedRectangleBorder( - borderRadius: - BorderRadius.circular( - 18, - ), + ); + + Utils.hapticFeedback(); + }, + onLongPressEnd: (details) { + controller.isAnyAlarmHolded + .value = false; + }, + child: AnimatedContainer( + duration: const Duration( + milliseconds: 600, + ), + curve: Curves.easeInOut, + margin: EdgeInsets.all( + controller.isAnyAlarmHolded + .value + ? 10 + : 0, + ), + child: Center( + child: Padding( + padding: const EdgeInsets + .symmetric( + horizontal: 10.0, ), - child: Center( - child: Padding( - padding: - EdgeInsets.only( - left: 25.0, - right: controller - .inMultipleSelectMode - .value - ? 10.0 - : 0.0, - top: controller - .inMultipleSelectMode - .value - ? Utils.isChallengeEnabled( - alarm, - ) || - Utils.isAutoDismissalEnabled( - alarm, - ) - ? 15.0 - : 18.0 - : Utils.isChallengeEnabled( - alarm, - ) || - Utils.isAutoDismissalEnabled( - alarm, - ) - ? 8.0 - : 0.0, - bottom: controller - .inMultipleSelectMode - .value - ? Utils.isChallengeEnabled( - alarm, - ) || - Utils.isAutoDismissalEnabled( - alarm, - ) - ? 15.0 - : 18.0 - : Utils.isChallengeEnabled( - alarm, - ) || - Utils.isAutoDismissalEnabled( - alarm, - ) - ? 8.0 - : 0.0, + child: Card( + color: themeController + .isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + shape: + RoundedRectangleBorder( + borderRadius: + BorderRadius + .circular( + 18, ), - child: Row( - mainAxisAlignment: - MainAxisAlignment - .start, - children: [ - Expanded( - flex: 3, - child: Column( - mainAxisAlignment: - MainAxisAlignment - .center, - crossAxisAlignment: - CrossAxisAlignment - .start, - children: [ - IntrinsicHeight( - child: Row( - children: [ - Text( - repeatDays - .replaceAll( - 'Never'.tr, - 'One Time'.tr, - ), - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - fontWeight: FontWeight.w500, - color: alarm.isEnabled == true - ? kprimaryColor - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - if (alarm - .label - .isNotEmpty) - VerticalDivider( - color: alarm.isEnabled == true - ? kprimaryColor - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - thickness: - 1.4, - width: - 6, - indent: - 3.1, - endIndent: - 3.1, - ), - Expanded( - child: - Container( - child: - Text( - alarm.label, - overflow: TextOverflow.ellipsis, - // Set overflow property here - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w500, - color: alarm.isEnabled == true - ? kprimaryColor - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), + ), + child: Center( + child: Padding( + padding: + EdgeInsets.only( + left: 25.0, + right: controller + .inMultipleSelectMode + .value + ? 10.0 + : 0.0, + top: controller + .inMultipleSelectMode + .value + ? Utils.isChallengeEnabled( + alarm, + ) || + Utils.isAutoDismissalEnabled( + alarm, + ) + ? 15.0 + : 18.0 + : Utils.isChallengeEnabled( + alarm, + ) || + Utils.isAutoDismissalEnabled( + alarm, + ) + ? 8.0 + : 0.0, + bottom: controller + .inMultipleSelectMode + .value + ? Utils.isChallengeEnabled( + alarm, + ) || + Utils.isAutoDismissalEnabled( + alarm, + ) + ? 15.0 + : 18.0 + : Utils.isChallengeEnabled( + alarm, + ) || + Utils.isAutoDismissalEnabled( + alarm, + ) + ? 8.0 + : 0.0, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment + .start, + children: [ + Expanded( + flex: 3, + child: Column( + mainAxisAlignment: + MainAxisAlignment + .center, + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + IntrinsicHeight( + child: + Row( + children: [ + Text( + repeatDays.replaceAll( + 'Never'.tr, + 'One Time'.tr, ), + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w500, + color: alarm.isEnabled == true + ? kprimaryColor + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - ), - ], - ), - ), - Row( - children: [ - Text( - (settingsController.is24HrsEnabled.value - ? Utils.split24HourFormat(alarm.alarmTime) - : Utils.convertTo12HourFormat( - alarm.alarmTime, - ))[0], - style: Theme - .of( - context, - ) - .textTheme - .displayLarge! - .copyWith( + if (alarm + .label + .isNotEmpty) + VerticalDivider( color: alarm.isEnabled == true - ? themeController.isLightMode.value - ? kLightPrimaryTextColor - : kprimaryTextColor + ? kprimaryColor : themeController.isLightMode.value ? kLightPrimaryDisabledTextColor : kprimaryDisabledTextColor, + thickness: 1.4, + width: 6, + indent: 3.1, + endIndent: 3.1, + ), + Expanded( + child: + Container( + child: Text( + alarm.label, + overflow: TextOverflow.ellipsis, + // Set overflow property here + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w500, + color: alarm.isEnabled == true + ? kprimaryColor + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), ), + ), + ], ), - Padding( - padding: - const EdgeInsets.symmetric( - horizontal: - 3.0, - ), - child: - Text( + ), + Row( + children: [ + Text( (settingsController.is24HrsEnabled.value ? Utils.split24HourFormat(alarm.alarmTime) : Utils.convertTo12HourFormat( alarm.alarmTime, - ))[1], - style: Theme.of(context) - .textTheme - .displayMedium! - .copyWith( + ))[0], + style: Theme.of( + context, + ).textTheme.displayLarge!.copyWith( color: alarm.isEnabled == true ? themeController.isLightMode.value ? kLightPrimaryTextColor @@ -1013,345 +1012,381 @@ class HomeView extends GetView { : kprimaryDisabledTextColor, ), ), - ), - ], - ), - if (Utils - .isChallengeEnabled( - alarm, - ) || - Utils - .isAutoDismissalEnabled( - alarm, - ) || - alarm - .isSharedAlarmEnabled) - Row( - mainAxisAlignment: - MainAxisAlignment - .start, - children: [ - if (alarm - .isSharedAlarmEnabled) - Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 3.0, - ), - child: - Icon( - Icons.share_arrival_time, - size: 24, - color: alarm.isEnabled == true - ? themeController.isLightMode.value - ? kLightPrimaryTextColor.withOpacity(0.5) - : kprimaryTextColor.withOpacity(0.5) - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), + Padding( + padding: + const EdgeInsets.symmetric( + horizontal: + 3.0, ), - if (alarm - .isLocationEnabled) - Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 3.0, - ), - child: - Icon( - Icons.location_pin, - size: 24, - color: alarm.isEnabled == true - ? themeController.isLightMode.value - ? kLightPrimaryTextColor.withOpacity(0.5) - : kprimaryTextColor.withOpacity(0.5) - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), + child: + Text( + (settingsController.is24HrsEnabled.value + ? Utils.split24HourFormat(alarm.alarmTime) + : Utils.convertTo12HourFormat( + alarm.alarmTime, + ))[1], + style: Theme.of(context).textTheme.displayMedium!.copyWith( + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - if (alarm - .isActivityEnabled) - Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 3.0, + ), + ], + ), + if (Utils + .isChallengeEnabled( + alarm, + ) || + Utils + .isAutoDismissalEnabled( + alarm, + ) || + alarm + .isSharedAlarmEnabled) + Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + if (alarm + .isSharedAlarmEnabled) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 3.0, + ), + child: Icon( + Icons.share_arrival_time, + size: 24, + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.5) + : kprimaryTextColor.withOpacity(0.5) + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - child: - Icon( - Icons.screen_lock_portrait, - size: 24, - color: alarm.isEnabled == true - ? themeController.isLightMode.value - ? kLightPrimaryTextColor.withOpacity(0.5) - : kprimaryTextColor.withOpacity(0.5) - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + if (alarm + .isLocationEnabled) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 3.0, + ), + child: Icon( + Icons.location_pin, + size: 24, + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.5) + : kprimaryTextColor.withOpacity(0.5) + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - ), - if (alarm - .isWeatherEnabled) - Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 3.0, + if (alarm + .isActivityEnabled) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 3.0, + ), + child: Icon( + Icons.screen_lock_portrait, + size: 24, + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.5) + : kprimaryTextColor.withOpacity(0.5) + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - child: - Icon( - Icons.cloudy_snowing, - size: 24, - color: alarm.isEnabled == true - ? themeController.isLightMode.value - ? kLightPrimaryTextColor.withOpacity(0.5) - : kprimaryTextColor.withOpacity(0.5) - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + if (alarm + .isWeatherEnabled) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 3.0, + ), + child: Icon( + Icons.cloudy_snowing, + size: 24, + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.5) + : kprimaryTextColor.withOpacity(0.5) + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - ), - if (alarm - .isQrEnabled) - Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 3.0, + if (alarm + .isQrEnabled) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 3.0, + ), + child: Icon( + Icons.qr_code_scanner, + size: 24, + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.5) + : kprimaryTextColor.withOpacity(0.5) + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - child: - Icon( - Icons.qr_code_scanner, - size: 24, - color: alarm.isEnabled == true - ? themeController.isLightMode.value - ? kLightPrimaryTextColor.withOpacity(0.5) - : kprimaryTextColor.withOpacity(0.5) - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + if (alarm + .isPhotochallengeEnabled) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 3.0, + ), + child: Icon( + Icons.camera_alt, + size: 24, + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.5) + : kprimaryTextColor.withOpacity(0.5) + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - ), - if (alarm - .isShakeEnabled) - Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 3.0, + if (alarm + .isShakeEnabled) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 3.0, + ), + child: Icon( + Icons.vibration, + size: 24, + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.5) + : kprimaryTextColor.withOpacity(0.5) + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - child: - Icon( - Icons.vibration, - size: 24, - color: alarm.isEnabled == true - ? themeController.isLightMode.value - ? kLightPrimaryTextColor.withOpacity(0.5) - : kprimaryTextColor.withOpacity(0.5) - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + if (alarm + .isMathsEnabled) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 3.0, + ), + child: Icon( + Icons.calculate, + size: 24, + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.5) + : kprimaryTextColor.withOpacity(0.5) + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - ), - if (alarm - .isMathsEnabled) - Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 3.0, + if (alarm + .isPedometerEnabled) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 3.0, + ), + child: Icon( + Icons.directions_walk, + size: 24, + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor.withOpacity(0.5) + : kprimaryTextColor.withOpacity(0.5) + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), + ], + ), + ], + ), + ), + Padding( + padding: + const EdgeInsets + .symmetric( + horizontal: + 10.0, + ), + child: controller + .inMultipleSelectMode + .value + ? Column( + // Showing the toggle button + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + flex: + 0, child: - Icon( - Icons.calculate, - size: 24, - color: alarm.isEnabled == true - ? themeController.isLightMode.value - ? kLightPrimaryTextColor.withOpacity(0.5) - : kprimaryTextColor.withOpacity(0.5) - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + ToggleButton( + controller: controller, + alarmIndex: index, ), ), - if (alarm - .isPedometerEnabled) - Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 3.0, - ), + ], + ) + : Column( + // Showing the switch and pop up menu button + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + flex: + 0, child: - Icon( - Icons.directions_walk, - size: 24, - color: alarm.isEnabled == true - ? themeController.isLightMode.value - ? kLightPrimaryTextColor.withOpacity(0.5) - : kprimaryTextColor.withOpacity(0.5) - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - ], - ), - ], - ), - ), - Padding( - padding: - const EdgeInsets - .symmetric( - horizontal: - 10.0, - ), - child: controller - .inMultipleSelectMode - .value - ? Column( - // Showing the toggle button - mainAxisAlignment: - MainAxisAlignment - .center, - children: [ - Expanded( - flex: - 0, - child: - ToggleButton( - controller: - controller, - alarmIndex: - index, - ), - ), - ], - ) - : Column( - // Showing the switch and pop up menu button - mainAxisAlignment: - MainAxisAlignment - .center, - children: [ - Expanded( - flex: - 0, - child: - Switch.adaptive( - activeColor: - ksecondaryColor, - value: - alarm.isEnabled, - onChanged: - (bool value) async { - Utils.hapticFeedback(); - alarm.isEnabled = value; - if (alarm.isSharedAlarmEnabled == true) { - await FirestoreDb.updateAlarm(alarm.ownerId, alarm); - } else { - await IsarDb.updateAlarm(alarm); - } - controller.refreshTimer = true; - controller.refreshUpcomingAlarms(); - }, - ), - ), - Expanded( - flex: - 0, - child: - PopupMenuButton( - onSelected: - (value) async { - Utils.hapticFeedback(); - if (value == 0) { - Get.back(); - Get.offNamed('/alarm-ring', arguments: alarm); - } else if (value == 1) { - debugPrint(alarm.isSharedAlarmEnabled.toString()); - + Switch.adaptive( + activeColor: ksecondaryColor, + value: alarm.isEnabled, + onChanged: (bool value) async { + Utils.hapticFeedback(); + alarm.isEnabled = value; if (alarm.isSharedAlarmEnabled == true) { - await FirestoreDb.deleteAlarm(controller.userModel.value, alarm.firestoreId!); + await FirestoreDb.updateAlarm(alarm.ownerId, alarm); } else { - await IsarDb.deleteAlarm(alarm.isarId); + await IsarDb.updateAlarm(alarm); } + controller.refreshTimer = true; + controller.refreshUpcomingAlarms(); + }, + ), + ), + Expanded( + flex: + 0, + child: + PopupMenuButton( + onSelected: (value) async { + Utils.hapticFeedback(); + if (value == 0) { + Get.back(); + Get.offNamed('/alarm-ring', arguments: alarm); + } else if (value == 1) { + debugPrint(alarm.isSharedAlarmEnabled.toString()); - if (Get.isSnackbarOpen) { - Get.closeAllSnackbars(); - } + if (alarm.isSharedAlarmEnabled == true) { + await FirestoreDb.deleteAlarm(controller.userModel.value, alarm.firestoreId!); + } else { + if (await File(alarm.imageurl).exists()) { + // Get the temporary directory - Get.snackbar( - 'Alarm deleted', - 'The alarm has been deleted.', - duration: const Duration(seconds: 4), - snackPosition: SnackPosition.BOTTOM, - margin: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 15, - ), - mainButton: TextButton( - onPressed: () async { - if (alarm.isSharedAlarmEnabled == true) { - await FirestoreDb.addAlarm(controller.userModel.value, alarm); - } else { - await IsarDb.addAlarm(alarm); - } - }, - child: const Text('Undo'), - ), - ); + Directory tempDir = await getTemporaryDirectory(); - String ringtoneName = alarm.ringtoneName; + // Generate a unique filename for the temporary copy + String tempFileName = '${DateTime.now().millisecondsSinceEpoch}.jpg'; - await AudioUtils.updateRingtoneCounterOfUsage( - customRingtoneName: ringtoneName, - counterUpdate: CounterUpdate.decrement, - ); + // Create a temporary file path + String tempFilePath = '${tempDir.path}/$tempFileName'; + // Copy the content of the original file to the temporary file + await File(alarm.imageurl).copy(tempFilePath); + // Store the temporary file path in the map + String alarmid = alarm.alarmID; + controller.deletedAlarmsMap[alarmid] = tempFilePath; + await controller.deleteFileIfExists(alarm.imageurl); + } - controller.refreshTimer = true; - controller.refreshUpcomingAlarms(); - } - }, - color: themeController.isLightMode.value - ? kLightPrimaryBackgroundColor - : kprimaryBackgroundColor, - icon: - Icon( - Icons.more_vert, - color: alarm.isEnabled == true - ? themeController.isLightMode.value - ? kLightPrimaryTextColor - : kprimaryTextColor - : themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - itemBuilder: - (context) { - return [ - PopupMenuItem( - value: 0, - child: Text( - 'Preview Alarm'.tr, - style: Theme.of(context).textTheme.bodyMedium, - ), - ), - if (alarm.isSharedAlarmEnabled == false || (alarm.isSharedAlarmEnabled == true && alarm.ownerId == controller.userModel.value!.id)) + await IsarDb.deleteAlarm(alarm.isarId); + } + + if (Get.isSnackbarOpen) { + Get.closeAllSnackbars(); + } + + Get.snackbar( + 'Alarm deleted', + 'The alarm has been deleted.', + duration: const Duration(seconds: 4), + snackPosition: SnackPosition.BOTTOM, + margin: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 15, + ), + mainButton: TextButton( + onPressed: () async { + if (alarm.isSharedAlarmEnabled == true) { + await FirestoreDb.addAlarm(controller.userModel.value, alarm); + } else { + if (controller.deletedAlarmsMap[alarm.alarmID] != null && await File(controller.deletedAlarmsMap[alarm.alarmID]!).exists()) { + await File(controller.deletedAlarmsMap[alarm.alarmID]!).copy(alarm.imageurl); + // Remove the alarm from the temporary storage + controller.deletedAlarmsMap.remove(alarm.alarmID); + } + await IsarDb.addAlarm(alarm); + } + }, + child: const Text('Undo'), + ), + ); + + String ringtoneName = alarm.ringtoneName; + + await AudioUtils.updateRingtoneCounterOfUsage( + customRingtoneName: ringtoneName, + counterUpdate: CounterUpdate.decrement, + ); + + controller.refreshTimer = true; + controller.refreshUpcomingAlarms(); + } + }, + color: themeController.isLightMode.value ? kLightPrimaryBackgroundColor : kprimaryBackgroundColor, + icon: Icon( + Icons.more_vert, + color: alarm.isEnabled == true + ? themeController.isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor + : themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + itemBuilder: (context) { + return [ PopupMenuItem( - value: 1, + value: 0, child: Text( - 'Delete Alarm'.tr, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Colors.red, - ), + 'Preview Alarm'.tr, + style: Theme.of(context).textTheme.bodyMedium, ), ), - ]; - }, + if (alarm.isSharedAlarmEnabled == false || (alarm.isSharedAlarmEnabled == true && alarm.ownerId == controller.userModel.value!.id)) + PopupMenuItem( + value: 1, + child: Text( + 'Delete Alarm'.tr, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: Colors.red, + ), + ), + ), + ]; + }, + ), ), - ), - ], - ), - ), - ], + ], + ), + ), + ], + ), ), ), ), @@ -1360,31 +1395,106 @@ class HomeView extends GetView { ), ), ), - ), - ); - }, - ); - } - }, - ); - } else { - return const CircularProgressIndicator.adaptive( - backgroundColor: Colors.transparent, - valueColor: AlwaysStoppedAnimation( - kprimaryColor, - ), - ); - } - }, - ); - }), + ); + }, + ); + } + }, + ); + } else { + return const CircularProgressIndicator.adaptive( + backgroundColor: Colors.transparent, + valueColor: AlwaysStoppedAnimation( + kprimaryColor, + ), + ); + } + }, + ); + }), + ), + ), + ], + ), + ), + ), + ), + ), + ); + } + + Future showDeleteAlarmConfirmationPopupOnSwipe( + BuildContext context, + ) async { + // Return true if user confirms deletion, false if canceled + + var result = await Get.defaultDialog( + titlePadding: const EdgeInsets.symmetric( + vertical: 20, + ), + backgroundColor: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + title: 'Confirmation'.tr, + titleStyle: Theme.of(context).textTheme.displaySmall, + content: Column( + children: [ + Text( + 'want to delete?'.tr, + style: Theme.of(context).textTheme.bodyMedium, + textAlign: TextAlign.center, + ), + Padding( + padding: const EdgeInsets.only( + top: 20, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: () { + Get.back(result: false); + }, + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'No'.tr, + style: Theme.of(context).textTheme.displaySmall!.copyWith( + color: kprimaryBackgroundColor, + ), + ), + ), + TextButton( + onPressed: () { + Get.back(result: true); // User confirmed + }, + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'Yes'.tr, + style: Theme.of(context).textTheme.displaySmall!.copyWith( + color: kprimaryBackgroundColor, + ), ), ), ], ), ), - ), + ], ), ); + + return result ?? + false; // Default to false if the user dismisses the dialog without tapping any button + } + + void refresh(BuildContext context) async { + await Get.offNamedUntil( + '/bottom-navigation-bar', + (route) => route.settings.name == '/splash-screen', + ); + await Future.delayed(const Duration(seconds: 3)); } } diff --git a/lib/app/modules/settings/views/customize_undo_duration.dart b/lib/app/modules/settings/views/customize_undo_duration.dart new file mode 100644 index 00000000..7262b997 --- /dev/null +++ b/lib/app/modules/settings/views/customize_undo_duration.dart @@ -0,0 +1,137 @@ + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get/get_core/src/get_main.dart'; +import 'package:ultimate_alarm_clock/app/modules/home/controllers/home_controller.dart'; + +import '../../../utils/constants.dart'; +import '../../../utils/utils.dart'; +import '../controllers/theme_controller.dart'; +import 'package:ultimate_alarm_clock/app/modules/settings/controllers/settings_controller.dart'; + +class CustomizeUndoDuration extends StatelessWidget{ + HomeController homeController = Get.find(); + CustomizeUndoDuration({ + super.key , + required this.themeController, + required this.height, + required this.width, + }); + final ThemeController themeController; + final double width; + final double height; + + @override + Widget build(BuildContext context) { + int duration; + return InkWell( + onTap: () { + Utils.hapticFeedback(); + duration = homeController.duration.value; + Get.defaultDialog( + onWillPop: () async { + Get.back(); + // Resetting the value to its initial state + homeController.duration.value = duration; + return true; + }, + titlePadding: const EdgeInsets.symmetric(vertical: 20, horizontal: 5), + backgroundColor: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + title: 'Customize Undo Duration'.tr, + titleStyle: Theme.of(context).textTheme.displaySmall, + content: Obx( + () => Column( + children: [ + Text( + '${homeController.duration.value} seconds'.tr, + style: Theme.of(context).textTheme.displaySmall, + ), + Slider( + value: homeController.selecteddurationDouble.value, + onChanged: (double value) { + homeController.selecteddurationDouble.value = value; + homeController.duration.value = value.toInt(); + + }, + min: 0.0, + max: 20.0, + divisions: 20, + label: homeController.duration.value.toString(), + ), + // Replace the volMin Slider with RangeSlider + + ElevatedButton( + onPressed: () { + Get.back(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: kprimaryColor, + ), + child: Text( + 'Apply Duration'.tr, + style: TextStyle( + color: themeController.isLightMode.value + ? kLightSecondaryTextColor + : ksecondaryTextColor, + ), + ), + ), + ], + ), + ), + ); + }, + child: Container( + width: width * 0.91, + height: height * 0.09, + decoration: Utils.getCustomTileBoxDecoration( + isLightMode: themeController.isLightMode.value, + ), + child: Center( + child: Padding( + padding: EdgeInsets.only(left: 10, right: 10), + child: ListTile( + tileColor: themeController.isLightMode.value + ? kLightSecondaryBackgroundColor + : ksecondaryBackgroundColor, + title: Text( + 'Undo Duration'.tr, + style: TextStyle( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor, + fontSize: 15 + ), + ), + trailing: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Obx( + () => Text( + '${homeController.duration.value.round().toInt()} seconds', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: themeController.isLightMode.value + ? kLightPrimaryTextColor + : kprimaryTextColor, + fontSize: 13 + ), + ), + ), + Icon( + Icons.chevron_right, + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ], + ), + ), + ), + ) + ) + ); + } + +} \ No newline at end of file diff --git a/lib/app/modules/settings/views/settings_view.dart b/lib/app/modules/settings/views/settings_view.dart index 20eb31c8..2dbc1704 100644 --- a/lib/app/modules/settings/views/settings_view.dart +++ b/lib/app/modules/settings/views/settings_view.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:ultimate_alarm_clock/app/modules/home/controllers/home_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; +import 'package:ultimate_alarm_clock/app/modules/settings/views/customize_undo_duration.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/views/enable_24Hour_format.dart'; @@ -110,6 +111,14 @@ class SettingsView extends GetView { const SizedBox( height: 20, ), + CustomizeUndoDuration( + width: width, + height: height, + themeController: controller.themeController + ), + const SizedBox( + height: 20, + ), LanguageMenu( controller: controller, height: height, diff --git a/lib/app/modules/settings/views/weather_api.dart b/lib/app/modules/settings/views/weather_api.dart index af44c5ac..43b290a9 100644 --- a/lib/app/modules/settings/views/weather_api.dart +++ b/lib/app/modules/settings/views/weather_api.dart @@ -110,7 +110,9 @@ class WeatherApi extends StatelessWidget { .value = true; // Validation If String is empty - if (controller.apiKey.text.isEmpty) { + if (controller.apiKey.text + .trim() + .isEmpty) { // setState(() { controller.isApiKeyEmpty.value = true; @@ -122,8 +124,9 @@ class WeatherApi extends StatelessWidget { } // Reset state after getting error message - if (controller - .apiKey.text.isNotEmpty) { + if (controller.apiKey.text + .trim() + .isNotEmpty) { // setState(() { controller.isApiKeyEmpty.value = false; diff --git a/lib/app/modules/timer/bindings/timer_binding.dart b/lib/app/modules/timer/bindings/timer_binding.dart index 603d88b0..541d2dd8 100644 --- a/lib/app/modules/timer/bindings/timer_binding.dart +++ b/lib/app/modules/timer/bindings/timer_binding.dart @@ -1,4 +1,6 @@ import 'package:get/get.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/bottomNavigationBar/controllers/bottom_navigation_bar_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/home/controllers/home_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/settings_controller.dart'; diff --git a/lib/app/modules/timer/controllers/timer_controller.dart b/lib/app/modules/timer/controllers/timer_controller.dart index 25fcd1a5..574b45bd 100644 --- a/lib/app/modules/timer/controllers/timer_controller.dart +++ b/lib/app/modules/timer/controllers/timer_controller.dart @@ -18,7 +18,7 @@ class TimerController extends GetxController with WidgetsBindingObserver { Rx countdownTimer = Rx(null); AlarmModel alarmRecord = Utils.genFakeAlarmModel(); late int currentTimerIsarId; - var hours=0.obs, minutes=1.obs, seconds=0.obs; + var hours = 0.obs, minutes = 1.obs, seconds = 0.obs; final _secureStorageProvider = SecureStorageProvider(); @@ -37,15 +37,6 @@ class TimerController extends GetxController with WidgetsBindingObserver { super.onClose(); } - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - super.didChangeAppLifecycleState(state); - - if (state == AppLifecycleState.resumed) { - loadTimerStateFromStorage(); - } - } - void saveTimerStateToStorage() async { await _secureStorageProvider.writeRemainingTimeInSeconds( remainingTimeInSeconds: remainingTime.value.inSeconds, diff --git a/lib/app/modules/timer/views/timer_view.dart b/lib/app/modules/timer/views/timer_view.dart index 065dd95c..d51a81ea 100644 --- a/lib/app/modules/timer/views/timer_view.dart +++ b/lib/app/modules/timer/views/timer_view.dart @@ -1,8 +1,10 @@ +import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:numberpicker/numberpicker.dart'; import 'package:ultimate_alarm_clock/app/data/providers/isar_provider.dart'; import 'package:ultimate_alarm_clock/app/data/providers/secure_storage_provider.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/timer/controllers/timer_controller.dart'; import 'package:ultimate_alarm_clock/app/routes/app_pages.dart'; @@ -14,6 +16,7 @@ class TimerView extends GetView { TimerView({Key? key}) : super(key: key); ThemeController themeController = Get.find(); + InputTimeController inputTimeController = Get.put(InputTimeController()); @override Widget build(BuildContext context) { @@ -51,10 +54,9 @@ class TimerView extends GetView { body: Obx( () => controller.isTimerRunning.value ? Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - SizedBox( - height: height * 0.3, - ), Center( child: Obx( () { @@ -76,7 +78,7 @@ class TimerView extends GetView { Expanded( child: Center( child: Text( - '$hours', + hours, style: const TextStyle( fontSize: 50.0, fontWeight: FontWeight.bold, @@ -94,7 +96,7 @@ class TimerView extends GetView { Expanded( child: Center( child: Text( - '$minutes', + minutes, style: const TextStyle( fontSize: 50.0, fontWeight: FontWeight.bold, @@ -112,7 +114,7 @@ class TimerView extends GetView { Expanded( child: Center( child: Text( - '$seconds', + seconds, style: const TextStyle( fontSize: 50.0, fontWeight: FontWeight.bold, @@ -125,15 +127,10 @@ class TimerView extends GetView { }, ), ), - SizedBox( - height: height * 0.15, - ), Obx( () => Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ - SizedBox( - width: width * 0.20, - ), FloatingActionButton.small( heroTag: 'stop', onPressed: () async { @@ -168,246 +165,462 @@ class TimerView extends GetView { ), ], ) - : Obx( - () => Container( - color: themeController.isLightMode.value - ? kLightPrimaryBackgroundColor - : kprimaryBackgroundColor, - height: height * 0.32, - width: width, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Hours', - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - fontWeight: FontWeight.bold, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - SizedBox( - height: height * 0.008, - ), - NumberPicker( - minValue: 0, - maxValue: 23, - value: controller.hours.value, - onChanged: (value) { - Utils.hapticFeedback(); - controller.hours.value = value; - }, - infiniteLoop: true, - itemWidth: width * 0.17, - zeroPad: true, - selectedTextStyle: Theme.of(context) - .textTheme - .displayLarge! - .copyWith( - fontWeight: FontWeight.bold, - color: kprimaryColor, - ), - textStyle: Theme.of(context) - .textTheme - .displayMedium! - .copyWith( - fontSize: 20, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - decoration: BoxDecoration( - border: Border( - top: BorderSide( - width: width * 0.005, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + : InkWell( + onTap: () { + Utils.hapticFeedback(); + inputTimeController.changeTimePickerTimer(); + }, + child: Obx( + () => Container( + color: themeController.isLightMode.value + ? kLightPrimaryBackgroundColor + : kprimaryBackgroundColor, + height: height * 0.32, + width: width, + child: inputTimeController.isTimePickerTimer.value + ? Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Hours', + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + fontWeight: FontWeight.bold, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + SizedBox( + height: height * 0.008, + ), + NumberPicker( + minValue: 0, + maxValue: 23, + value: controller.hours.value, + onChanged: (value) { + Utils.hapticFeedback(); + controller.hours.value = value; + }, + infiniteLoop: true, + itemWidth: width * 0.17, + zeroPad: true, + selectedTextStyle: Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: kprimaryColor, + ), + textStyle: Theme.of(context) + .textTheme + .displayMedium! + .copyWith( + fontSize: 20, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: width * 0.005, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + bottom: BorderSide( + width: width * 0.005, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + ), + ), + ], + ), + Padding( + padding: EdgeInsets.only( + left: width * 0.02, + right: width * 0.02, + top: height * 0.035, ), - bottom: BorderSide( - width: width * 0.005, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + child: Text( + ':', + style: Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), ), - ), - ), - ], - ), - Padding( - padding: EdgeInsets.only( - left: width * 0.02, - right: width * 0.02, - top: height * 0.035, - ), - child: Text( - ':', - style: Theme.of(context) - .textTheme - .displayLarge! - .copyWith( - fontWeight: FontWeight.bold, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Minutes', + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + fontWeight: FontWeight.bold, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + SizedBox( + height: height * 0.008, + ), + NumberPicker( + minValue: 0, + maxValue: 59, + value: controller.minutes.value, + onChanged: (value) { + controller.minutes.value = value; + }, + infiniteLoop: true, + itemWidth: width * 0.17, + zeroPad: true, + selectedTextStyle: Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: kprimaryColor, + ), + textStyle: Theme.of(context) + .textTheme + .displayMedium! + .copyWith( + fontSize: 20, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: width * 0.005, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + bottom: BorderSide( + width: width * 0.005, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + ), + ), + ], ), - ), - ), - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Minutes', - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - fontWeight: FontWeight.bold, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - SizedBox( - height: height * 0.008, - ), - NumberPicker( - minValue: 0, - maxValue: 59, - value: controller.minutes.value, - onChanged: (value) { - controller.minutes.value = value; - }, - infiniteLoop: true, - itemWidth: width * 0.17, - zeroPad: true, - selectedTextStyle: Theme.of(context) - .textTheme - .displayLarge! - .copyWith( - fontWeight: FontWeight.bold, - color: kprimaryColor, - ), - textStyle: Theme.of(context) - .textTheme - .displayMedium! - .copyWith( - fontSize: 20, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - decoration: BoxDecoration( - border: Border( - top: BorderSide( - width: width * 0.005, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + Padding( + padding: EdgeInsets.only( + left: width * 0.02, + right: width * 0.02, + top: height * 0.035, ), - bottom: BorderSide( - width: width * 0.005, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + child: Text( + ':', + style: Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), ), - ), - ), - ], - ), - Padding( - padding: EdgeInsets.only( - left: width * 0.02, - right: width * 0.02, - top: height * 0.035, - ), - child: Text( - ':', - style: Theme.of(context) - .textTheme - .displayLarge! - .copyWith( - fontWeight: FontWeight.bold, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Seconds', + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + fontWeight: FontWeight.bold, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + SizedBox( + height: height * 0.008, + ), + NumberPicker( + minValue: 0, + maxValue: 59, + value: controller.seconds.value, + onChanged: (value) { + controller.seconds.value = value; + }, + infiniteLoop: true, + itemWidth: width * 0.17, + zeroPad: true, + selectedTextStyle: Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: kprimaryColor, + ), + textStyle: Theme.of(context) + .textTheme + .displayMedium! + .copyWith( + fontSize: 20, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: width * 0.005, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + bottom: BorderSide( + width: width * 0.005, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + ), + ), + ], ), - ), - ), - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Seconds', - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - fontWeight: FontWeight.bold, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), - ), - SizedBox( - height: height * 0.008, - ), - NumberPicker( - minValue: 0, - maxValue: 59, - value: controller.seconds.value, - onChanged: (value) { - controller.seconds.value = value; - }, - infiniteLoop: true, - itemWidth: width * 0.17, - zeroPad: true, - selectedTextStyle: Theme.of(context) - .textTheme - .displayLarge! - .copyWith( - fontWeight: FontWeight.bold, - color: kprimaryColor, + ], + ) + : Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Hours', + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + fontWeight: FontWeight.bold, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + SizedBox( + height: height * 0.008, + ), + SizedBox( + width: 80, + child: TextField( + onChanged: (_) { + inputTimeController.setTimerTime(); + }, + decoration: const InputDecoration( + hintText: 'HH', + border: InputBorder.none, + ), + textAlign: TextAlign.center, + controller: inputTimeController + .inputHoursControllerTimer, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp( + '[1,2,3,4,5,6,7,8,9,0]', + ), + ), + LengthLimitingTextInputFormatter( + 2, + ), + LimitRange( + 0, + 23, + ), + ], + ), + ), + ], + ), + Padding( + padding: EdgeInsets.only( + left: width * 0.02, + right: width * 0.02, + top: height * 0.035, ), - textStyle: Theme.of(context) - .textTheme - .displayMedium! - .copyWith( - fontSize: 20, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + child: Text( + ':', + style: Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), - decoration: BoxDecoration( - border: Border( - top: BorderSide( - width: width * 0.005, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Minutes', + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + fontWeight: FontWeight.bold, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + SizedBox( + height: height * 0.008, + ), + SizedBox( + width: 80, + child: TextField( + onChanged: (_) { + inputTimeController.setTimerTime(); + }, + decoration: const InputDecoration( + hintText: 'MM', + border: InputBorder.none, + ), + textAlign: TextAlign.center, + controller: inputTimeController + .inputMinutesControllerTimer, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp( + '[1,2,3,4,5,6,7,8,9,0]', + ), + ), + LengthLimitingTextInputFormatter( + 2, + ), + LimitRange( + 0, + 59, + ), + ], + ), + ), + ], + ), + Padding( + padding: EdgeInsets.only( + left: width * 0.02, + right: width * 0.02, + top: height * 0.035, ), - bottom: BorderSide( - width: width * 0.005, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, + child: Text( + ':', + style: Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: themeController.isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), ), ), - ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Seconds', + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + fontWeight: FontWeight.bold, + color: themeController + .isLightMode.value + ? kLightPrimaryDisabledTextColor + : kprimaryDisabledTextColor, + ), + ), + SizedBox( + height: height * 0.008, + ), + SizedBox( + width: 80, + child: TextField( + onChanged: (_) { + inputTimeController.setTimerTime(); + }, + decoration: const InputDecoration( + hintText: 'SS', + border: InputBorder.none, + ), + textAlign: TextAlign.center, + controller: inputTimeController + .inputSecondsControllerTimer, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp( + '[1,2,3,4,5,6,7,8,9,0]', + ), + ), + LengthLimitingTextInputFormatter( + 2, + ), + LimitRange( + 0, + 59, + ), + ], + ), + ), + ], + ), + ], ), - ], - ), - ], ), ), ), @@ -446,7 +659,7 @@ class TimerView extends GetView { ), ), ), - endDrawer: buildEndDrawer(context) + endDrawer: buildEndDrawer(context), ); } } diff --git a/lib/app/utils/audio_utils.dart b/lib/app/utils/audio_utils.dart index 146866e7..544aa49d 100644 --- a/lib/app/utils/audio_utils.dart +++ b/lib/app/utils/audio_utils.dart @@ -14,7 +14,7 @@ class AudioUtils { static MethodChannel alarmChannel = const MethodChannel('ulticlock'); static AudioSession? audioSession; - + static bool isPreviewing = false; static Future initializeAudioSession() async { @@ -92,8 +92,6 @@ class AudioUtils { } } - - static Future stopDefaultAlarm() async { try { if (audioSession != null) { @@ -115,6 +113,7 @@ class AudioUtils { if (ringtoneName == 'Default') { await alarmChannel.invokeMethod('playDefaultAlarm'); + isPreviewing = true; } else { int customRingtoneId = fastHash(ringtoneName); RingtoneModel? customRingtone = await IsarDb.getCustomRingtone( @@ -128,10 +127,7 @@ class AudioUtils { await audioSession!.setActive(true); await playCustomSound(customRingtonePath); isPreviewing = true; - } else { - await alarmChannel.invokeMethod('playDefaultAlarm'); - isPreviewing = true; - } + } } } catch (e) { debugPrint(e.toString()); diff --git a/lib/app/utils/constants.dart b/lib/app/utils/constants.dart index 5b5b19df..11e42791 100644 --- a/lib/app/utils/constants.dart +++ b/lib/app/utils/constants.dart @@ -120,12 +120,24 @@ ThemeData kThemeData = ThemeData( backgroundColor: kprimaryBackgroundColor, selectedLabelStyle: TextStyle( color: kprimaryColor, + shadows: [ + Shadow(color: Color.fromARGB(90, 255, 255, 255), offset: Offset(1, 1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(90, 255, 255, 255), offset: Offset(1, -1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(90, 255, 255, 255), offset: Offset(-1, 1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(90, 255, 255, 255), offset: Offset(-1, -1), blurRadius: 10.0), + ], ), unselectedLabelStyle: TextStyle( color: kprimaryTextColor, ), selectedIconTheme: IconThemeData( color: kprimaryColor, + shadows: [ + Shadow(color: Color.fromARGB(90, 255, 255, 255), offset: Offset(1, 1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(90, 255, 255, 255), offset: Offset(1, -1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(90, 255, 255, 255), offset: Offset(-1, 1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(90, 255, 255, 255), offset: Offset(-1, -1), blurRadius: 10.0), + ], ), unselectedIconTheme: IconThemeData( color: kprimaryTextColor, @@ -219,12 +231,24 @@ ThemeData kLightThemeData = ThemeData( backgroundColor: kLightPrimaryBackgroundColor, selectedLabelStyle: TextStyle( color: kprimaryColor, + shadows: [ + Shadow(color: Color.fromARGB(120, 0, 0, 0), offset: Offset(1, 1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(120, 0, 0, 0), offset: Offset(1, -1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(120, 0, 0, 0), offset: Offset(-1, 1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(120, 0, 0, 0), offset: Offset(-1, -1), blurRadius: 10.0), + ], ), unselectedLabelStyle: TextStyle( color: kLightPrimaryTextColor, ), selectedIconTheme: IconThemeData( color: kprimaryColor, + shadows: [ + Shadow(color: Color.fromARGB(100, 0, 0, 0), offset: Offset(1, 1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(100, 0, 0, 0), offset: Offset(1, -1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(100, 0, 0, 0), offset: Offset(-1, 1), blurRadius: 10.0), + Shadow(color: Color.fromARGB(100, 0, 0, 0), offset: Offset(-1, -1), blurRadius: 10.0), + ], ), unselectedIconTheme: IconThemeData( color: kLightPrimaryTextColor, diff --git a/lib/app/utils/language.dart b/lib/app/utils/language.dart index c8b7945f..7cd36d0f 100644 --- a/lib/app/utils/language.dart +++ b/lib/app/utils/language.dart @@ -53,6 +53,11 @@ class AppTranslations extends Translations { 'Create alarm': 'Create alarm', 'Join alarm': 'Join alarm', 'Okay': 'Okay', + 'Yes': 'Yes', + 'No': 'No', + 'Confirmation': 'Confirmation', + 'want to delete?': 'Are you sure you want to delete this alarm?', + 'You cannot join your own alarm!': 'You cannot join your own alarm!', 'An alarm with this ID doesn\'t exist!': 'An alarm with this ID doesn\'t exist!', @@ -81,7 +86,7 @@ class AppTranslations extends Translations { 'Leave': 'Leave', 'Save': 'Save', 'Update': 'Update', - 'Rings in @timeToAlarm': 'Rings in @timeToAlarm', + // 'Rings in @timeToAlarm': 'Rings in @timeToAlarm', 'Uh-oh!': 'Uh-oh!', 'alarmEditing': 'This alarm is currently being edited!', 'Go back': 'Go back', @@ -129,6 +134,17 @@ class AppTranslations extends Translations { 'QR/Bar Code': 'QR/Bar Code', 'qrDescription': 'Scan the QR/Bar code on any object, like a book, and relocate it to a different room. To deactivate the alarm, simply rescan the same QR/Bar code.', + //photo_challenge_tile.dart + 'Take': 'Take', + 'Retake': 'Retake', + 'Disable': 'Disable', + 'Photo': 'Photo', + 'photoDescription': + 'The ultimate photo challenge app that turns capturing moments into an exhilarating game! Snap a shot to kickstart the challenge, then race against the clock to recreate it and silence the alarm. Are you up for the challenge?', + + 'Take Photo': 'Tak1 Photo', + 'Capture a Photo': 'Capture a Photo', + //repeat_once_tile.dart 'Repeat only once': 'Repeat only once', //repeat_tile.dart @@ -152,7 +168,7 @@ class AppTranslations extends Translations { 'times': 'times', 'time': 'time', //'shared_alarm_tile.dart - 'Shared Alarm': 'Shared Alarm', + // 'Shared Alarm': 'Shared Alarm', 'Shared alarms': 'Shared alarms', 'sharedDescription': 'Share alarms with others using the Alarm ID. Each shared user can choose to have their alarm ring before or after the set time.', @@ -191,7 +207,7 @@ class AppTranslations extends Translations { //qr_challenge_view.dart 'Scan your QR/Bar Code!': 'Scan your QR/Bar Code!', 'Wrong Code Scanned!': 'Wrong Code Scanned!', - 'Retake': 'Retake', + //shake_challenge_view.dart 'Shake your phone!': 'Shake your phone!', //alarm_ring_view.dart diff --git a/lib/app/utils/languages/french_translations.dart b/lib/app/utils/languages/french_translations.dart index a187f770..926848fa 100644 --- a/lib/app/utils/languages/french_translations.dart +++ b/lib/app/utils/languages/french_translations.dart @@ -52,6 +52,11 @@ class FrenchTranslations extends Translations { 'Create alarm': 'Créer un réveil', 'Join alarm': 'Rejoindre un réveil', 'Okay': 'D\'accord', + 'Yes': 'Oui', + 'No': 'Non', + 'Confirmation': 'Confirmation', + 'want to delete?': + 'Êtes-vous sûr de vouloir supprimer cette alarme ?', 'You cannot join your own alarm!': 'Vous ne pouvez pas rejoindre votre propre réveil !', 'An alarm with this ID doesn\'t exist!': @@ -157,6 +162,16 @@ class FrenchTranslations extends Translations { 'QR/Bar Code': 'QR/Code-barres', 'qrDescription': 'Scannez le QR/Code-barres sur n\'importe quel objet, comme un livre, et déplacez-le dans une pièce différente. Pour désactiver l\'alarme, scannez à nouveau le même QR/Code-barres.', + +//photo_challenge_tile.dart + 'Take': 'Prendre', + 'Retake': 'Reprendre', + 'Disable': 'Désactiver', + 'Photo': 'Photo', + 'photoDescription': + "L'application ultime de défi photo qui transforme la capture de moments en un jeu palpitant ! Prenez une photo pour lancer le défi, puis défiez le temps pour la recréer et arrêter l'alarme. Êtes-vous prêt pour le défi ?", + 'Take Photo': 'Prendre une photo', + 'Capture a Photo': 'Capturer une photo', //repeat_once_tile.dart 'Repeat only once': 'Répéter une seule fois', //repeat_tile.dart diff --git a/lib/app/utils/languages/german_translations.dart b/lib/app/utils/languages/german_translations.dart index e07e6159..a36b8bf2 100644 --- a/lib/app/utils/languages/german_translations.dart +++ b/lib/app/utils/languages/german_translations.dart @@ -45,6 +45,11 @@ class GermanTranslations extends Translations { 'Create alarm': 'Alarm erstellen', 'Join alarm': 'Alarm beitreten', 'Okay': 'Okay', + 'Yes': 'Ja', + 'No': 'Nein', + 'Confirmation': 'Bestätigung', + 'want to delete?': + 'Sind Sie sicher, dass Sie diesen Alarm löschen möchten?', 'You cannot join your own alarm!': 'Sie können Ihrem eigenen Alarm nicht beitreten!', 'An alarm with this ID doesn\'t exist!': @@ -152,6 +157,17 @@ class GermanTranslations extends Translations { 'QR/Bar Code': 'QR-/Strichcode', 'qrDescription': 'Scannen Sie den QR-/Strichcode auf einem Objekt wie einem Buch und verschieben Sie es in einen anderen Raum. Zum Deaktivieren des Alarms scannen Sie einfach denselben QR-/Strichcode erneut.', +//photo_challenge_tile.dart + + 'Take': 'Aufnehmen', + 'Retake': 'Erneut aufnehmen', + 'Disable': 'Deaktivieren', + 'Photo': 'Foto', + 'photoDescription': + 'Die ultimative Foto-Challenge-App, die das Erfassen von Momenten in ein aufregendes Spiel verwandelt! Machen Sie ein Foto, um die Herausforderung zu starten, und versuchen Sie dann, es schnellstmöglich nachzustellen, um den Alarm zu stoppen. Sind Sie bereit für die Herausforderung?', + 'Take Photo': 'Foto machen', + 'Capture a Photo': 'Foto aufnehmen', + //repeat_once_tile.dart 'Repeat only once': 'Nur einmal wiederholen', //repeat_tile.dart diff --git a/lib/app/utils/languages/russian_translations.dart b/lib/app/utils/languages/russian_translations.dart index b66cbd57..e3e5b660 100644 --- a/lib/app/utils/languages/russian_translations.dart +++ b/lib/app/utils/languages/russian_translations.dart @@ -51,6 +51,10 @@ class RussianTranslations extends Translations { 'Create alarm': 'Создать будильник', 'Join alarm': 'Присоединиться к будильнику', 'Okay': 'Хорошо', + 'Yes': 'Да', + 'No': 'Нет', + 'Confirmation': 'подтверждение', + 'want to delete?': 'Вы уверены, что хотите удалить этот будильник?', 'You cannot join your own alarm!': 'Вы не можете присоединиться к собственной тревоге!', 'An alarm with this ID doesn\'t exist!': @@ -141,6 +145,15 @@ class RussianTranslations extends Translations { 'QR/Bar Code': 'QR-код / Штрих-код', 'qrDescription': 'Отсканируйте QR-код / Штрих-код на любом объекте, например, на книге, и переместите его в другую комнату. Чтобы отключить будильник, просто повторно отсканируйте тот же QR-код / Штрих-код.', +//photo_challenge_tile.dart + 'Take': 'Сделать', + 'Retake': 'Переснять', + 'Disable': 'Отключить', + 'Photo': 'Фото', + 'photoDescription': + 'Это приложение для фотовызовов, которое превращает запечатление моментов в захватывающую игру! Сделайте снимок, чтобы начать вызов, затем соревнуйтесь с временем, чтобы воссоздать его и выключить сигнал тревоги. Готовы ли вы к вызову?', + 'Take Photo': 'Сделать фото', + 'Capture a Photo': 'Захватить фотографию', //repeat_once_tile.dart 'Repeat only once': 'Повторять только один раз', //repeat_tile.dart diff --git a/lib/app/utils/languages/spanish_translations.dart b/lib/app/utils/languages/spanish_translations.dart index ffd6ed48..9fb70c7b 100644 --- a/lib/app/utils/languages/spanish_translations.dart +++ b/lib/app/utils/languages/spanish_translations.dart @@ -52,6 +52,11 @@ class SpanishTranslations extends Translations { 'Create alarm': 'Crear alarma', 'Join alarm': 'Unirse a alarma', 'Okay': 'Aceptar', + 'Yes': 'Sí', + 'No': 'No', + 'Confirmation': 'Confirmación', + 'want to delete?': + '¿Estás seguro de que deseas eliminar esta alarma?', 'You cannot join your own alarm!': '¡No puedes unirte a tu propia alarma!', 'An alarm with this ID doesn\'t exist!': @@ -155,6 +160,16 @@ class SpanishTranslations extends Translations { 'QR/Bar Code': 'Código QR/Código de barras', 'qrDescription': 'Escanee el código QR/código de barras en cualquier objeto, como un libro, y muévalo a una habitación diferente. Para desactivar la alarma, simplemente vuelva a escanear el mismo código QR/código de barras.', +//photo_challenge_tile.dart + 'Tomar': 'Tomar', + 'Volver a tomar': 'Volver a tomar', + 'Desactivar': 'Desactivar', + 'Foto': 'Foto', + 'photoDescription': + '¡La aplicación definitiva de desafío fotográfico que convierte la captura de momentos en un emocionante juego! Toma una foto para comenzar el desafío, luego compite contra el reloj para recrearla y silenciar la alarma. ¿Estás listo para el desafío?', + 'Take Photo': 'Tomar foto', + 'Capture a Photo': 'Capturar una foto', + //repeat_once_tile.dart 'Repeat only once': 'Repetir solo una vez', //repeat_tile.dart diff --git a/lib/app/utils/utils.dart b/lib/app/utils/utils.dart index dea1e6c1..a50c8b31 100644 --- a/lib/app/utils/utils.dart +++ b/lib/app/utils/utils.dart @@ -371,6 +371,8 @@ class Utils { mathsDifficulty: 0, qrValue: '', isQrEnabled: false, + imageurl: '', + isPhotochallengeEnabled: false, isShakeEnabled: false, shakeTimes: 0, isPedometerEnabled: false, @@ -509,9 +511,11 @@ class Utils { if (alarmRecord.isMathsEnabled || alarmRecord.isQrEnabled || alarmRecord.isShakeEnabled || - alarmRecord.isPedometerEnabled) { + alarmRecord.isPedometerEnabled || + alarmRecord.isPhotochallengeEnabled) { return true; } + return false; } @@ -562,6 +566,7 @@ class Utils { ? kLightSecondaryBackgroundColor : ksecondaryBackgroundColor, builder: (context) { + Get.log(description.tr); return Center( child: Padding( padding: const EdgeInsets.all(25.0), diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 96159719..69bc572f 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -16,6 +17,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 77f89fdb..c08964ad 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux + file_selector_linux flutter_secure_storage_linux flutter_volume_controller isar_flutter_libs diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 5028a563..e2dfa37b 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,7 +9,9 @@ import audio_session import audioplayers_darwin import cloud_firestore import device_info_plus +import file_selector_macos import firebase_core +import firebase_storage import flutter_secure_storage_macos import flutter_volume_controller import google_sign_in_ios @@ -23,7 +25,9 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) FlutterVolumeControllerPlugin.register(with: registry.registrar(forPlugin: "FlutterVolumeControllerPlugin")) FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 5ef61bee..70ce4b4e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: f5628cd9c92ed11083f425fd1f8f1bc60ecdda458c81d73b143aeda036c35fe7 + sha256: "737321f9be522620ed3794937298fb0027a48a402624fa2500f7532f94aea810" url: "https://pub.dev" source: hosted - version: "1.3.16" + version: "1.3.22" analyzer: dependency: transitive description: @@ -265,6 +265,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + url: "https://pub.dev" + source: hosted + version: "0.3.3+8" crypto: dependency: transitive description: @@ -353,14 +361,46 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" + url: "https://pub.dev" + source: hosted + version: "0.9.2+1" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" firebase_core: dependency: "direct main" description: name: firebase_core - sha256: "96607c0e829a581c2a483c658f04e8b159964c3bae2730f73297070bc85d40bb" + sha256: "7e049e32a9d347616edb39542cf92cd53fdb4a99fb6af0a0bff327c14cd76445" url: "https://pub.dev" source: hosted - version: "2.24.2" + version: "2.25.4" firebase_core_platform_interface: dependency: transitive description: @@ -373,10 +413,34 @@ packages: dependency: transitive description: name: firebase_core_web - sha256: d585bdf3c656c3f7821ba1bd44da5f13365d22fcecaf5eb75c4295246aaa83c0 + sha256: "57e61d6010e253b36d38191cefd6199d7849152cdcd234b61ca290cdb278a0ba" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.4" + firebase_storage: + dependency: "direct main" + description: + name: firebase_storage + sha256: a07433d3ffe948f7a10086e4b0bd3a940be4ed873cffd24746eed1896b568369 + url: "https://pub.dev" + source: hosted + version: "11.6.6" + firebase_storage_platform_interface: + dependency: transitive + description: + name: firebase_storage_platform_interface + sha256: af99d9fcf058d6f3a591cea899cad054ded7adb21fb1788dfe65c3e223196b15 + url: "https://pub.dev" + source: hosted + version: "5.1.9" + firebase_storage_web: + dependency: transitive + description: + name: firebase_storage_web + sha256: "06a684016de9609928865798dece0f7d34782a15a76f5ac08bd3a8780035b0b2" + url: "https://pub.dev" + source: hosted + version: "3.7.0" fixnum: dependency: transitive description: @@ -564,10 +628,10 @@ packages: dependency: "direct main" description: name: get - sha256: "2ba20a47c8f1f233bed775ba2dd0d3ac97b4cf32fc17731b3dfc672b06b0e92a" + sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e url: "https://pub.dev" source: hosted - version: "4.6.5" + version: "4.6.6" get_storage: dependency: "direct main" description: @@ -673,13 +737,85 @@ packages: source: hosted version: "4.0.2" image: - dependency: transitive + dependency: "direct main" description: name: image - sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d" + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" + url: "https://pub.dev" + source: hosted + version: "4.1.7" + image_compare_2: + dependency: "direct main" + description: + name: image_compare_2 + sha256: "50ff6f6a793f61fc5b19e9ad7bf1bb9507e57b73ec689332eed11c1473954807" + url: "https://pub.dev" + source: hosted + version: "1.1.7" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "26222b01a0c9a2c8fe02fc90b8208bd3325da5ed1f4a2acabf75939031ac0bdd" + url: "https://pub.dev" + source: hosted + version: "1.0.7" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1" + url: "https://pub.dev" + source: hosted + version: "0.8.9+3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: e2423c53a68b579a7c37a1eda967b8ae536c3d98518e5db95ca1fe5719a730a3 + url: "https://pub.dev" + source: hosted + version: "3.0.2" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: fadafce49e8569257a0cad56d24438a6fa1f0cbd7ee0af9b631f7492818a4ca3 + url: "https://pub.dev" + source: hosted + version: "0.8.9+1" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: fa4e815e6fcada50e35718727d83ba1c92f1edf95c0b4436554cec301b56233b + url: "https://pub.dev" + source: hosted + version: "2.9.3" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" url: "https://pub.dev" source: hosted - version: "4.1.4" + version: "0.2.1+1" infinite_listview: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b6d81f36..43f51f28 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,13 +10,15 @@ dependencies: firebase_core: ^2.8.0 screen_state: ^2.0.0 cupertino_icons: ^1.0.2 - get: 4.6.5 + get: 4.6.6 get_storage: ^2.1.1 flutter_time_picker_spinner: ^2.0.0 cloud_firestore: ^4.4.5 intl: ^0.18.0 latlong2: ^0.8.1 flutter_map: ^4.0.0 + image: ^4.1.7 + image_compare_2: ^1.1.7 fl_location: ^2.0.0+1 flutter_fgbg: ^0.3.0 flutter_svg: ^2.0.4 @@ -45,6 +47,8 @@ dependencies: uuid: ^4.3.3 pedometer: ^4.0.1 flutter_volume_controller: ^1.3.1 + image_picker: ^1.0.7 + firebase_storage: ^11.6.6 dev_dependencies: flutter_lints: ^2.0.3 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index ba8f0aa7..9f10abe9 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,7 +8,9 @@ #include #include +#include #include +#include #include #include #include @@ -20,8 +22,12 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); CloudFirestorePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("CloudFirestorePluginCApi")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); FirebaseCorePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); + FirebaseStoragePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); FlutterVolumeControllerPluginCApiRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 66c746d7..ecd34d1e 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,7 +5,9 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows cloud_firestore + file_selector_windows firebase_core + firebase_storage flutter_secure_storage_windows flutter_volume_controller isar_flutter_libs