diff --git a/.github/workflows/create_release_on_tag.yml b/.github/workflows/create_release_on_tag.yml index 61407422..c1cf0c60 100644 --- a/.github/workflows/create_release_on_tag.yml +++ b/.github/workflows/create_release_on_tag.yml @@ -10,15 +10,18 @@ jobs: name: Create Release and Upload APK runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@master - - - name: Set up JDK 1.8 - uses: actions/setup-java@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 with: distribution: 'adopt' # See 'Supported distributions' for available options java-version: '17' + # - name: Set up JDK 17 + # uses: actions/setup-java@v4 + # with: + # distribution: 'adopt' # See 'Supported distributions' for available options + # java-version: '17' + - name: Cache Flutter id: cache-flutter uses: actions/cache@v3 @@ -28,6 +31,16 @@ jobs: ~/.pub-cache key: flutter-${{ hashFiles('**/pubspec.lock') }} + - name: Cache Gradle + id: cache-gradle + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper/ + key: gradle-ubuntu-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + + - if: ${{ steps.cache-flutter.outputs.cache-hit != 'true' }} name: Install Flutter run: git clone https://github.com/flutter/flutter.git --depth 1 -b stable $FOLDER diff --git a/CHANGELOG.md b/CHANGELOG.md index 1760de8a..80549beb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 4.2.0 + +* moving to carp_themes_package instead of research package themes +* partially transitioning from pods to spm +* health connect flow update +* informed consent accepted is now checked via API instead of local settings +* fixing hasSeenBluetoothInstructions bool logic +* small UI changes + ## 4.1.1 - small visual fixes diff --git a/android/app/build.gradle b/android/app/build.gradle index e70b25af..bc2192c5 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -5,7 +5,7 @@ plugins { } def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') +def localPropertiesFile = project.rootProject.file('local.properties') if (localPropertiesFile.exists()) { localPropertiesFile.withReader('UTF-8') { reader -> localProperties.load(reader) @@ -13,7 +13,7 @@ if (localPropertiesFile.exists()) { } def keyProperties = new Properties() -def keyPropertiesFile = rootProject.file('key.properties') +def keyPropertiesFile = project.rootProject.file('key.properties') def signingConfigExists = false if (keyPropertiesFile.exists()) { @@ -23,15 +23,8 @@ if (keyPropertiesFile.exists()) { } } -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') ?: '1' +def flutterVersionName = localProperties.getProperty('flutter.versionName') ?: '1.0' android { namespace "dk.carp.studies_app" @@ -88,10 +81,10 @@ android { debugSymbolLevel 'SYMBOL_TABLE' } if (signingConfigExists) { - logger.error('storeFile found, signing with release build.') + logger.info('storeFile found, signing with release build.') signingConfig signingConfigs.release } else { - logger.error('No storeFile found or null. Skipping signing of release build.') + logger.info('No storeFile found or null. Skipping signing of release build.') signingConfig signingConfigs.debug } } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 303b83a4..0356ad36 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -212,29 +212,6 @@ --> - - - - - - - - - - - 'https://bitbucket.org/movesense/movesense-mobile-lib/' - pod 'PhoneNumberKit', '~> 3.7' + # pod 'PhoneNumberKit', '~> 3.7' end post_install do |installer| diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a1758e56..087ce02c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,52 +1,21 @@ PODS: - - AppAuth (2.0.0): - - AppAuth/Core (= 2.0.0) - - AppAuth/ExternalUserAgent (= 2.0.0) - - AppAuth/Core (2.0.0) - - AppAuth/ExternalUserAgent (2.0.0): - - AppAuth/Core - - "appcheck (1.5.4+1)": - - Flutter - - audio_session (0.0.1): - - Flutter - audio_streamer (0.0.1): - Flutter - - battery_plus (1.0.0): - - Flutter - - camera_avfoundation (0.0.1): - - Flutter - - connectivity_plus (0.0.1): - - Flutter - dchs_flutter_beacon (0.6.5): - Flutter - - device_info_plus (0.0.1): - - Flutter - Flutter (1.0.0) - flutter_activity_recognition (0.0.1): - Flutter - - flutter_appauth (0.0.1): - - AppAuth (= 2.0.0) - - Flutter - - flutter_blue_plus_darwin (0.0.2): - - Flutter - - FlutterMacOS - - flutter_local_notifications (0.0.1): - - Flutter - flutter_secure_storage (6.0.0): - Flutter - flutter_sound (9.28.0): - Flutter - flutter_sound_core (= 9.28.0) - flutter_sound_core (9.28.0) - - flutter_timezone (0.0.1): - - Flutter - flutter_web_auth_2 (3.0.0): - Flutter - health (12.2.1): - Flutter - - just_audio (0.0.1): - - Flutter - - FlutterMacOS - location (0.0.1): - Flutter - mdsflutter (0.0.1): @@ -55,27 +24,14 @@ PODS: - SwiftProtobuf - Movesense (3.33.1) - MTBBarcodeScanner (5.0.11) - - network_info_plus (0.0.1): - - Flutter - oidc_ios (0.0.1): - Flutter - open_settings_plus (0.0.1): - Flutter - - package_info_plus (0.4.5): - - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - pedometer (0.0.1): - Flutter - permission_handler_apple (9.3.0): - Flutter - - PhoneNumberKit (3.8.0): - - PhoneNumberKit/PhoneNumberKitCore (= 3.8.0) - - PhoneNumberKit/UIKit (= 3.8.0) - - PhoneNumberKit/PhoneNumberKitCore (3.8.0) - - PhoneNumberKit/UIKit (3.8.0): - - PhoneNumberKit/PhoneNumberKitCore - polar (0.0.1): - Flutter - PolarBleSdk (~> 6.1.0) @@ -89,128 +45,65 @@ PODS: - RxSwift (6.8.0) - screen_state (1.0.0): - Flutter - - sensors_plus (0.0.1): - - Flutter - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - sqflite_darwin (0.0.4): - - Flutter - - FlutterMacOS - - SwiftProtobuf (1.31.1) - - url_launcher_ios (0.0.1): - - Flutter - - video_player_avfoundation (0.0.1): - - Flutter - - FlutterMacOS + - SwiftProtobuf (1.33.3) - Zip (2.1.2) DEPENDENCIES: - - appcheck (from `.symlinks/plugins/appcheck/ios`) - - audio_session (from `.symlinks/plugins/audio_session/ios`) - audio_streamer (from `.symlinks/plugins/audio_streamer/ios`) - - battery_plus (from `.symlinks/plugins/battery_plus/ios`) - - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) - - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - dchs_flutter_beacon (from `.symlinks/plugins/dchs_flutter_beacon/ios`) - - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) - flutter_activity_recognition (from `.symlinks/plugins/flutter_activity_recognition/ios`) - - flutter_appauth (from `.symlinks/plugins/flutter_appauth/ios`) - - flutter_blue_plus_darwin (from `.symlinks/plugins/flutter_blue_plus_darwin/darwin`) - - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - flutter_sound (from `.symlinks/plugins/flutter_sound/ios`) - - flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`) - flutter_web_auth_2 (from `.symlinks/plugins/flutter_web_auth_2/ios`) - health (from `.symlinks/plugins/health/ios`) - - just_audio (from `.symlinks/plugins/just_audio/darwin`) - location (from `.symlinks/plugins/location/ios`) - mdsflutter (from `.symlinks/plugins/mdsflutter/ios`) - Movesense (from `https://bitbucket.org/movesense/movesense-mobile-lib/`) - - network_info_plus (from `.symlinks/plugins/network_info_plus/ios`) - oidc_ios (from `.symlinks/plugins/oidc_ios/ios`) - open_settings_plus (from `.symlinks/plugins/open_settings_plus/ios`) - - package_info_plus (from `.symlinks/plugins/package_info_plus/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`) - - PhoneNumberKit (~> 3.7) - polar (from `.symlinks/plugins/polar/ios`) - qr_code_scanner_plus (from `.symlinks/plugins/qr_code_scanner_plus/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`) - - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) SPEC REPOS: trunk: - - AppAuth - flutter_sound_core - MTBBarcodeScanner - - PhoneNumberKit - PolarBleSdk - RxSwift - SwiftProtobuf - Zip EXTERNAL SOURCES: - appcheck: - :path: ".symlinks/plugins/appcheck/ios" - audio_session: - :path: ".symlinks/plugins/audio_session/ios" audio_streamer: :path: ".symlinks/plugins/audio_streamer/ios" - battery_plus: - :path: ".symlinks/plugins/battery_plus/ios" - camera_avfoundation: - :path: ".symlinks/plugins/camera_avfoundation/ios" - connectivity_plus: - :path: ".symlinks/plugins/connectivity_plus/ios" dchs_flutter_beacon: :path: ".symlinks/plugins/dchs_flutter_beacon/ios" - device_info_plus: - :path: ".symlinks/plugins/device_info_plus/ios" Flutter: :path: Flutter flutter_activity_recognition: :path: ".symlinks/plugins/flutter_activity_recognition/ios" - flutter_appauth: - :path: ".symlinks/plugins/flutter_appauth/ios" - flutter_blue_plus_darwin: - :path: ".symlinks/plugins/flutter_blue_plus_darwin/darwin" - flutter_local_notifications: - :path: ".symlinks/plugins/flutter_local_notifications/ios" flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" flutter_sound: :path: ".symlinks/plugins/flutter_sound/ios" - flutter_timezone: - :path: ".symlinks/plugins/flutter_timezone/ios" flutter_web_auth_2: :path: ".symlinks/plugins/flutter_web_auth_2/ios" health: :path: ".symlinks/plugins/health/ios" - just_audio: - :path: ".symlinks/plugins/just_audio/darwin" location: :path: ".symlinks/plugins/location/ios" mdsflutter: :path: ".symlinks/plugins/mdsflutter/ios" Movesense: :git: https://bitbucket.org/movesense/movesense-mobile-lib/ - network_info_plus: - :path: ".symlinks/plugins/network_info_plus/ios" oidc_ios: :path: ".symlinks/plugins/oidc_ios/ios" open_settings_plus: :path: ".symlinks/plugins/open_settings_plus/ios" - package_info_plus: - :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" pedometer: :path: ".symlinks/plugins/pedometer/ios" permission_handler_apple: @@ -221,16 +114,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/qr_code_scanner_plus/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" - sqflite_darwin: - :path: ".symlinks/plugins/sqflite_darwin/darwin" - url_launcher_ios: - :path: ".symlinks/plugins/url_launcher_ios/ios" - video_player_avfoundation: - :path: ".symlinks/plugins/video_player_avfoundation/darwin" CHECKOUT OPTIONS: Movesense: @@ -238,52 +121,31 @@ CHECKOUT OPTIONS: :git: https://bitbucket.org/movesense/movesense-mobile-lib/ SPEC CHECKSUMS: - AppAuth: 1c1a8afa7e12f2ec3a294d9882dfa5ab7d3cb063 - appcheck: 3c94d0ffc94bd639938cac7427d5b13df2795404 - audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0 audio_streamer: 2e472b9f81cec5e381c4cf7667afa3055dcb45a4 - battery_plus: b42253f6d2dde71712f8c36fef456d99121c5977 - camera_avfoundation: 5675ca25298b6f81fa0a325188e7df62cc217741 - connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd dchs_flutter_beacon: 88d72cc467de508d621e454ea66c6231d0897d4c - device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 flutter_activity_recognition: 52dfad4c1e9cec99f0841b3ed0efcc9d424b3deb - flutter_appauth: d4abcf54856e5d8ba82ed7646ffc83245d4aa448 - flutter_blue_plus_darwin: 20a08bfeaa0f7804d524858d3d8744bcc1b6dbc3 - flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13 flutter_sound: b9236a5875299aaa4cef1690afd2f01d52a3f890 flutter_sound_core: 427465f72d07ab8c3edbe8ffdde709ddacd3763c - flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544 flutter_web_auth_2: 5c8d9dcd7848b5a9efb086d24e7a9adcae979c80 health: fe206e65f13a9b88623605fbd8af8f029e23dc35 - just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed location: 155caecf9da4f280ab5fe4a55f94ceccfab838f8 mdsflutter: bd3c0b3335d50947d1a192cf70f930e0fb04a766 Movesense: dc64047c1feb856b7f7ac6ea2c67685350d99dd5 MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb - network_info_plus: cf61925ab5205dce05a4f0895989afdb6aade5fc oidc_ios: 16966cad509ce6850ca4ca1216c5138bef2a8726 open_settings_plus: d19f91e8a04649358a51c19b484ce2e637149d70 - package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 - path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 pedometer: 1c5eaab0c6bce8eb7651f7095553b5081c9d06ed permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d - PhoneNumberKit: ec00ab8cef5342c1dc49fadb99d23fa7e66cf0ef polar: 0374f6063ade7e2dd85d626f87cbe2393d3eda7c PolarBleSdk: bfb57cf8350f0c53d441b8632ba6df363ce7c79f qr_code_scanner_plus: 7e087021bc69873140e0754750eb87d867bed755 RxSwift: 4e28be97cbcfeee614af26d83415febbf2bf6f45 screen_state: 52d6e997d31bddba6417c60d9cdd22effd0320a7 - sensors_plus: 6a11ed0c2e1d0bd0b20b4029d3bad27d96e0c65b - shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb - sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 - SwiftProtobuf: e02f51c8c2df5845657aee2d4de9d61bf50ef788 - url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b - video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a + SwiftProtobuf: e1b437c8e31a4c5577b643249a0bb62ed4f02153 Zip: b3fef584b147b6e582b2256a9815c897d60ddc67 -PODFILE CHECKSUM: 0f233b2493d660073cf18073d2b24e7b319ab4a8 +PODFILE CHECKSUM: 45842edf150243fea66883d4dfad1e5ddb428147 COCOAPODS: 1.16.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 516f6216..d1a2b803 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -8,9 +8,11 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 1DF7245C2EC76C6800F24410 /* PhoneNumberKit in Frameworks */ = {isa = PBXBuildFile; productRef = 1DF7245B2EC76C6800F24410 /* PhoneNumberKit */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -53,6 +55,7 @@ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; @@ -78,6 +81,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 1DF7245C2EC76C6800F24410 /* PhoneNumberKit in Frameworks */, + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, D93ECDADCF301D48CCE6DCE8 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -106,6 +111,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -199,6 +205,10 @@ dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + 1DF7245B2EC76C6800F24410 /* PhoneNumberKit */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -233,6 +243,10 @@ da, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 1DF7245A2EC76C6800F24410 /* XCRemoteSwiftPackageReference "PhoneNumberKit" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -734,6 +748,36 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 1DF7245A2EC76C6800F24410 /* XCRemoteSwiftPackageReference "PhoneNumberKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/marmelroy/PhoneNumberKit.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 3.6.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 1DF7245B2EC76C6800F24410 /* PhoneNumberKit */ = { + isa = XCSwiftPackageProductDependency; + package = 1DF7245A2EC76C6800F24410 /* XCRemoteSwiftPackageReference "PhoneNumberKit" */; + productName = PhoneNumberKit; + }; + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..7f1c67b8 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,23 @@ +{ + "pins" : [ + { + "identity" : "appauth-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/openid/AppAuth-iOS", + "state" : { + "revision" : "145104f5ea9d58ae21b60add007c33c1cc0c948e", + "version" : "2.0.0" + } + }, + { + "identity" : "phonenumberkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/marmelroy/PhoneNumberKit.git", + "state" : { + "revision" : "c107075aa8d394be7aced273a46e944afe8b321b", + "version" : "3.8.0" + } + } + ], + "version" : 2 +} diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index fa4cdb69..e596a992 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + UIViewControllerBasedStatusBarAppearance - UIStatusBarHidden - diff --git a/lib/blocs/app_bloc.dart b/lib/blocs/app_bloc.dart index 18eca055..3fd87f5c 100644 --- a/lib/blocs/app_bloc.dart +++ b/lib/blocs/app_bloc.dart @@ -352,7 +352,9 @@ class StudyAppBLoC extends ChangeNotifier { /// Has the informed consent been accepted by the user? bool get hasInformedConsentBeenAccepted => - LocalSettings().participant?.hasInformedConsentBeenAccepted ?? false; + backend.getInformedConsentByRole( + study!.studyDeploymentId, study!.participantRoleName) != + null; set hasInformedConsentBeenAccepted(bool accepted) { var participant = LocalSettings().participant; @@ -380,6 +382,7 @@ class StudyAppBLoC extends ChangeNotifier { /// the Study Page of the app. Future refreshMessages() async { try { + _messages.clear(); _messages = await messageManager.getMessages(); _messages.sort((m1, m2) => m2.timestamp.compareTo(m1.timestamp)); info('Message list refreshed - count: ${_messages.length}'); @@ -478,14 +481,13 @@ class StudyAppBLoC extends ChangeNotifier { /// * resetting the informed consent flow /// * returning the user to select an invitation for another study /// - /// Note that study deployment information and data is not removed from the - /// phone. This is stored for later access. Or if the same deployment is - /// re-deployed on the phone, data from the previous deployment will be - /// available. + /// Note that study deployment information and data is removed from the + /// phone. If the same deployment is re-deployed on the phone, data from the + /// previous deployment will NOT be available. Future leaveStudy() async { - debug('$runtimeType --------- LEAVING STUDY ------------'); + info('Leaving study $study'); - // save and clear the UI data models + // clear the UI data models appViewModel.clear(); // stop sensing and remove all deployment info diff --git a/lib/carp_study_app.dart b/lib/carp_study_app.dart index 296c2360..43ac5389 100644 --- a/lib/carp_study_app.dart +++ b/lib/carp_study_app.dart @@ -183,7 +183,14 @@ class CarpStudyAppState extends State { @override Widget build(BuildContext context) { - final carpColors = Theme.of(context).extension(); + final studyAppColors = Theme.of(context).extension(); + + // Apply system overlay style after frame so Theme.of(context) is ready + WidgetsBinding.instance.addPostFrameCallback((_) { + SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + )); + }); return MaterialApp.router( scaffoldMessengerKey: bloc.scaffoldKey, supportedLocales: const [ @@ -211,14 +218,14 @@ class CarpStudyAppState extends State { return supportedLocales.first; // default to EN }, locale: bloc.localization?.locale, - theme: researchPackageTheme.copyWith( + theme: carpTheme.copyWith( extensions: [ - researchPackageTheme.extension()!.copyWith( - primary: carpColors?.primary, + carpTheme.extension()!.copyWith( + primary: studyAppColors?.primary, ), ], ), - darkTheme: researchPackageDarkTheme, + darkTheme: carpDarkTheme, debugShowCheckedModeBanner: true, routerConfig: _router, ); diff --git a/lib/data/carp_backend.dart b/lib/data/carp_backend.dart index 6f100fc3..3db20440 100644 --- a/lib/data/carp_backend.dart +++ b/lib/data/carp_backend.dart @@ -232,4 +232,11 @@ class CarpBackend { return uploadedConsent; } + + Future? getInformedConsentByRole( + String studyDeploymentId, String? role) async { + return await CarpParticipationService() + .participation(studyDeploymentId) + .getInformedConsentByRole(role); + } } diff --git a/lib/data/local_settings.dart b/lib/data/local_settings.dart index 086461d5..a5194c1a 100644 --- a/lib/data/local_settings.dart +++ b/lib/data/local_settings.dart @@ -14,9 +14,6 @@ class LocalSettings { /// See https://developer.android.com/health-and-fitness/guides/health-connect/develop/get-started#get-client static const healthConnectPackageName = 'com.google.android.apps.healthdata'; - bool isExpectedParticipantDataSet = false; - bool hasUserSeenDeviceConnectionInstructions = false; - // Keys for storing in shared preferences static const String userKey = 'user'; static const String participantKey = 'participant'; @@ -26,8 +23,6 @@ class LocalSettings { Participant? _participant; SmartphoneStudy? _study; - bool hasSeenBluetoothConnectionInstructions = false; - static final LocalSettings _instance = LocalSettings._(); factory LocalSettings() => _instance; LocalSettings._() : super(); @@ -109,11 +104,13 @@ class LocalSettings { ); } - bool get hasSeenConnectionInstructions => - hasSeenBluetoothConnectionInstructions; + bool get hasSeenBluetoothConnectionInstructions => + Settings() + .preferences + ?.getBool('hasSeenBluetoothConnectionInstructions') ?? + false; - set hasSeenConnectionInstructions(bool seen) { - hasSeenBluetoothConnectionInstructions = seen; + set hasSeenBluetoothConnectionInstructions(bool seen) { Settings().preferences?.setBool( 'hasSeenBluetoothConnectionInstructions', seen, diff --git a/lib/main.dart b/lib/main.dart index 904ffa4f..778eef6e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -55,6 +55,7 @@ import 'package:cognition_package/cognition_package.dart'; import 'package:carp_health_package/health_package.dart'; // import 'package:health/health.dart'; import 'package:carp_movesense_package/carp_movesense_package.dart'; +import 'package:carp_themes_package/carp_themes_package.dart'; part 'blocs/app_bloc.dart'; part 'blocs/util.dart'; @@ -105,8 +106,7 @@ part 'ui/pages/devices_page.enable_bluetooth_dialog.dart'; part 'ui/pages/devices_page.bluetooth_connection_page.dart'; part 'ui/pages/devices_page.disconnection_dialog.dart'; part 'ui/pages/devices_page.list_title.dart'; -part 'ui/pages/devices_page.health_service_connect1.dart'; -part 'ui/pages/devices_page.health_service_connect2.dart'; +part 'ui/pages/devices_page.health_service_connect.dart'; part 'ui/tasks/audio_task_page.dart'; part 'ui/tasks/audio_page.dart'; diff --git a/lib/ui/cards/activity_card.dart b/lib/ui/cards/activity_card.dart index 51bb84c8..68fe931f 100644 --- a/lib/ui/cards/activity_card.dart +++ b/lib/ui/cards/activity_card.dart @@ -63,7 +63,7 @@ class ActivityCardState extends State { RPLocalizations locale = RPLocalizations.of(context)!; return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.white!, + backgroundColor: Theme.of(context).extension()!.white!, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -72,16 +72,16 @@ class ActivityCardState extends State { children: [ Text( '${_walk! + _run! + _cycle!}', - style: dataVizCardTitleNumber.copyWith( - color: Theme.of(context).extension()!.grey900!, + style: fs28fw700.copyWith( + color: Theme.of(context).extension()!.grey900!, ), ), Padding( padding: const EdgeInsets.only(left: 4.0), child: Text( '${locale.translate('cards.activity.total.min')} ${_getDayName(touchedIndex)}', - style: dataVizCardTitleText.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), ), @@ -91,8 +91,8 @@ class ActivityCardState extends State { children: [ Text( "${widget.model.currentMonth} ${widget.model.startOfWeek} - ${int.parse(widget.model.endOfWeek) < int.parse(widget.model.startOfWeek) ? widget.model.nextMonth : widget.model.currentMonth} ${widget.model.endOfWeek}, ${widget.model.currentYear}", - style: dataVizCardTitleText.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), Spacer(), @@ -117,7 +117,7 @@ class ActivityCardState extends State { children: [ Text( '$_walk', - style: dataVizCardBottomNumber.copyWith( + style: fs22fw700.copyWith( color: widget.colors[0], ), ), @@ -125,9 +125,9 @@ class ActivityCardState extends State { padding: const EdgeInsets.all(4.0), child: Text( locale.translate('cards.activity.walking'), - style: dataVizCardBottomText.copyWith( + style: fs12fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey800), ), ), @@ -141,7 +141,7 @@ class ActivityCardState extends State { padding: const EdgeInsets.only(left: 8.0), child: Text( '$_run', - style: dataVizCardBottomNumber.copyWith( + style: fs12fw700.copyWith( color: widget.colors[1], ), ), @@ -150,9 +150,9 @@ class ActivityCardState extends State { padding: const EdgeInsets.all(4.0), child: Text( locale.translate('cards.activity.running'), - style: dataVizCardBottomText.copyWith( + style: fs12fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey800), ), ), @@ -165,7 +165,7 @@ class ActivityCardState extends State { children: [ Text( '$_cycle', - style: dataVizCardBottomNumber.copyWith( + style: fs22fw700.copyWith( color: widget.colors[2], ), ), @@ -173,9 +173,10 @@ class ActivityCardState extends State { padding: const EdgeInsets.only(left: 4.0), child: Text( locale.translate('cards.activity.cycling'), - style: dataVizCardBottomText.copyWith( - color: - Theme.of(context).extension()!.grey800, + style: fs12fw700.copyWith( + color: Theme.of(context) + .extension()! + .grey800, ), ), ), @@ -303,8 +304,8 @@ class ActivityCardState extends State { value.toInt() % meta.appliedInterval == 0 ? value.toInt().toString() : '', - style: dataCardRightTitleStyle.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs14ls1.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), ); diff --git a/lib/ui/cards/anonymous_card.dart b/lib/ui/cards/anonymous_card.dart index 1c935295..c135d51a 100644 --- a/lib/ui/cards/anonymous_card.dart +++ b/lib/ui/cards/anonymous_card.dart @@ -8,7 +8,7 @@ class AnonymousCard extends StatelessWidget { RPLocalizations locale = RPLocalizations.of(context)!; return Card( - color: Theme.of(context).extension()!.grey50, + color: Theme.of(context).extension()!.grey50, elevation: 0, margin: const EdgeInsets.all(16.0), shape: RoundedRectangleBorder( @@ -45,8 +45,7 @@ class AnonymousCard extends StatelessWidget { child: Text( locale.translate('pages.about.anonymous.anonymous'), maxLines: 2, - style: aboutCardSubtitleStyle.copyWith( - color: CACHET.ANONYMOUS), + style: fs16fw600.copyWith(color: CACHET.ANONYMOUS), ), ), ], @@ -56,9 +55,9 @@ class AnonymousCard extends StatelessWidget { padding: const EdgeInsets.only(left: 16.0), child: Text( locale.translate('pages.about.anonymous.message'), - style: aboutCardSubtitleStyle.copyWith( + style: fs16fw600.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900, fontSize: 14, ), diff --git a/lib/ui/cards/distance_card.dart b/lib/ui/cards/distance_card.dart index 92e06851..857ad3ae 100644 --- a/lib/ui/cards/distance_card.dart +++ b/lib/ui/cards/distance_card.dart @@ -33,7 +33,7 @@ class _DistanceCardState extends State { @override Widget build(BuildContext context) { return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.white!, + backgroundColor: Theme.of(context).extension()!.white!, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -42,16 +42,16 @@ class _DistanceCardState extends State { children: [ Text( _distance, - style: dataVizCardTitleNumber.copyWith( - color: Theme.of(context).extension()!.grey900!, + style: fs28fw700.copyWith( + color: Theme.of(context).extension()!.grey900!, ), ), Padding( padding: const EdgeInsets.only(left: 4.0), child: Text( 'km ${_getDayName(touchedIndex)}', - style: dataVizCardTitleText.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), ), @@ -61,8 +61,8 @@ class _DistanceCardState extends State { children: [ Text( "${widget.model.currentMonth} ${widget.model.startOfWeek} - ${int.parse(widget.model.endOfWeek) < int.parse(widget.model.startOfWeek) ? widget.model.nextMonth : widget.model.currentMonth} ${widget.model.endOfWeek}, ${widget.model.currentYear}", - style: dataVizCardTitleText.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), Spacer(), @@ -174,8 +174,8 @@ class _DistanceCardState extends State { value.toInt() % meta.appliedInterval == 0 ? value.toInt().toString() : '', - style: dataCardRightTitleStyle.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs14ls1.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), ); diff --git a/lib/ui/cards/heart_rate_card.dart b/lib/ui/cards/heart_rate_card.dart index abe6290a..570fc7de 100644 --- a/lib/ui/cards/heart_rate_card.dart +++ b/lib/ui/cards/heart_rate_card.dart @@ -42,7 +42,7 @@ class HeartRateCardWidgetState extends State @override Widget build(BuildContext context) { return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.white!, + backgroundColor: Theme.of(context).extension()!.white!, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -86,7 +86,7 @@ class HeartRateCardWidgetState extends State min == null || max == null ? '-' : '${(min.toInt())} - ${(max.toInt())}', - style: heartRateNumberStyle, + style: fs28fw700, ), ), Padding( @@ -95,9 +95,9 @@ class HeartRateCardWidgetState extends State min == null || max == null ? '' : locale.translate('cards.heartrate.bpm'), - style: heartRateBPMTextStyle.copyWith( + style: fs10fw700.copyWith( fontSize: 12, - color: Theme.of(context).extension()!.grey600, + color: Theme.of(context).extension()!.grey600, ), ), ), @@ -122,9 +122,9 @@ class HeartRateCardWidgetState extends State child: currentHeartRate != null ? Text( currentHeartRate.toStringAsFixed(0), - style: heartRateNumberStyle, + style: fs28fw700, ) - : Text('-', style: heartRateNumberStyle), + : Text('-', style: fs28fw700), ), Padding( padding: const EdgeInsets.only(bottom: 14), @@ -145,8 +145,9 @@ class HeartRateCardWidgetState extends State ), Text( locale.translate('cards.heartrate.bpm'), - style: heartRateBPMTextStyle.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs10fw700.copyWith( + color: + Theme.of(context).extension()!.grey600, ), ), ], @@ -169,7 +170,7 @@ class HeartRateCardWidgetState extends State enabled: true, touchTooltipData: BarTouchTooltipData( fitInsideHorizontally: true, - // tooltipBgColor: Theme.of(context).primaryColorLight, + fitInsideVertically: true, getTooltipItem: (group, groupIndex, rod, rodIndex) { return BarTooltipItem( '', @@ -210,7 +211,7 @@ class HeartRateCardWidgetState extends State ), ), ], - heartRateNumberStyle, + fs28fw700, ); }, ), @@ -310,8 +311,8 @@ class HeartRateCardWidgetState extends State value.toInt() % meta.appliedInterval == 0 ? value.toInt().toString() : '', - style: dataCardRightTitleStyle.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs14ls1.copyWith( + color: Theme.of(context).extension()!.grey600, ), maxLines: 1, ), diff --git a/lib/ui/cards/media_card.dart b/lib/ui/cards/media_card.dart index 1fe94b1c..c69d3c0f 100644 --- a/lib/ui/cards/media_card.dart +++ b/lib/ui/cards/media_card.dart @@ -19,7 +19,7 @@ class MediaCardWidgetState extends State { } return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.white!, + backgroundColor: Theme.of(context).extension()!.white!, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -34,7 +34,7 @@ class MediaCardWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 5), - Text('$total MEDIA', style: dataCardTitleStyle), + Text('$total MEDIA', style: fs16fw400ls1), Column( children: widget.modelsList .asMap() @@ -47,8 +47,8 @@ class MediaCardWidgetState extends State { const SizedBox(height: 15), Text( '${entry.value.tasksDone} ${locale.translate('cards.${entry.value.taskType}.title')}', - style: dataCardTitleStyle.copyWith( - fontSize: 14), + style: + fs16fw400ls1.copyWith(fontSize: 14), ), LayoutBuilder(builder: (BuildContext context, diff --git a/lib/ui/cards/mobility_card.dart b/lib/ui/cards/mobility_card.dart index ee506136..20278945 100644 --- a/lib/ui/cards/mobility_card.dart +++ b/lib/ui/cards/mobility_card.dart @@ -30,7 +30,7 @@ class _MobilityCardState extends State { RPLocalizations locale = RPLocalizations.of(context)!; return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.white!, + backgroundColor: Theme.of(context).extension()!.white!, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -39,7 +39,7 @@ class _MobilityCardState extends State { children: [ Text( '$_homestay%', - style: dataVizCardTitleNumber.copyWith( + style: fs28fw700.copyWith( color: widget.colors[0], ), ), @@ -47,8 +47,9 @@ class _MobilityCardState extends State { padding: const EdgeInsets.only(left: 4.0), child: Text( "${locale.translate('cards.mobility.homestay')} ${_getDayName(touchedIndex)}", - style: dataVizCardTitleText.copyWith( - color: Theme.of(context).extension()!.grey900!, + style: fs12fw700.copyWith( + color: + Theme.of(context).extension()!.grey900!, ), ), ), @@ -58,8 +59,8 @@ class _MobilityCardState extends State { children: [ Text( "${widget.model.currentMonth} ${widget.model.startOfWeek} - ${int.parse(widget.model.endOfWeek) < int.parse(widget.model.startOfWeek) ? widget.model.nextMonth : widget.model.currentMonth} ${widget.model.endOfWeek}, ${widget.model.currentYear}", - style: dataVizCardTitleText.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), Spacer(), @@ -81,7 +82,7 @@ class _MobilityCardState extends State { children: [ Text( '$_places', - style: dataVizCardBottomNumber.copyWith( + style: fs22fw700.copyWith( color: widget.colors[0], ), ), @@ -89,9 +90,9 @@ class _MobilityCardState extends State { padding: const EdgeInsets.all(4.0), child: Text( locale.translate('cards.mobility.places'), - style: dataVizCardBottomText.copyWith( + style: fs12fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey800), ), ), @@ -206,8 +207,8 @@ class _MobilityCardState extends State { value.toInt() % meta.appliedInterval == 0 ? value.toInt().toString() : '', - style: dataCardRightTitleStyle.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs14ls1.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), ); @@ -221,8 +222,8 @@ class _MobilityCardState extends State { value.toInt() % meta.appliedInterval == 0 ? value.toInt().toString() : '', - style: dataCardRightTitleStyle.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs14ls1.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), ); diff --git a/lib/ui/cards/scoreboard_card.dart b/lib/ui/cards/scoreboard_card.dart index 7ea6e62d..bcdc706e 100644 --- a/lib/ui/cards/scoreboard_card.dart +++ b/lib/ui/cards/scoreboard_card.dart @@ -54,41 +54,41 @@ class ScoreboardPersistentHeaderDelegate List childrenDays = [ Text(model.daysInStudy.toString(), - style: scoreNumberStyle.copyWith( - fontSize: calculateScrollAwareSizing(shrinkOffset, - scoreNumberStyleSmall.fontSize!, scoreNumberStyle.fontSize!), - color: Theme.of(context).extension()!.grey900)), + style: fs36fw800.copyWith( + fontSize: calculateScrollAwareSizing( + shrinkOffset, fs20fw800.fontSize!, fs36fw800.fontSize!), + color: Theme.of(context).extension()!.grey900)), if (shrinkOffset < offsetForShrink) Text(locale.translate('cards.scoreboard.days'), - style: scoreTextStyle.copyWith( - color: Theme.of(context).extension()!.grey900)), + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.grey900)), if (shrinkOffset > offsetForShrink) Padding( padding: const EdgeInsets.only(left: 8.0), child: Text(locale.translate('cards.scoreboard.days-short'), - style: scoreTextStyle.copyWith( - color: Theme.of(context).extension()!.grey900)), + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.grey900)), ) ]; List childrenTasks = [ Text(model.taskCompleted.toString(), - style: scoreNumberStyle.copyWith( - fontSize: calculateScrollAwareSizing(shrinkOffset, - scoreNumberStyleSmall.fontSize!, scoreNumberStyle.fontSize!), - color: Theme.of(context).extension()!.primary)), + style: fs36fw800.copyWith( + fontSize: calculateScrollAwareSizing( + shrinkOffset, fs20fw800.fontSize!, fs36fw800.fontSize!), + color: Theme.of(context).extension()!.primary)), if (shrinkOffset < offsetForShrink) Text(locale.translate('cards.scoreboard.tasks'), - style: scoreTextStyle.copyWith( - color: Theme.of(context).extension()!.primary)), + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.primary)), if (shrinkOffset > offsetForShrink) Expanded( flex: 0, child: Padding( padding: const EdgeInsets.only(left: 8.0), child: Text(locale.translate('cards.scoreboard.tasks-short'), - style: scoreTextStyle.copyWith( - color: Theme.of(context).extension()!.primary)), + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.primary)), ), ) ]; @@ -96,7 +96,7 @@ class ScoreboardPersistentHeaderDelegate return Container( height: height, decoration: BoxDecoration( - color: Theme.of(context).extension()!.white, + color: Theme.of(context).extension()!.white, borderRadius: BorderRadius.circular(8), // Rounded corners ), child: StreamBuilder( diff --git a/lib/ui/cards/steps_card.dart b/lib/ui/cards/steps_card.dart index f8caef84..ffb40e14 100644 --- a/lib/ui/cards/steps_card.dart +++ b/lib/ui/cards/steps_card.dart @@ -29,7 +29,7 @@ class StepsCardWidgetState extends State { RPLocalizations locale = RPLocalizations.of(context)!; return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.white!, + backgroundColor: Theme.of(context).extension()!.white!, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -37,17 +37,17 @@ class StepsCardWidgetState extends State { Row( children: [ Text( - '$_step', - style: dataVizCardTitleNumber.copyWith( - color: Theme.of(context).extension()!.grey900!, + _step > 0 ? '$_step' : '0', + style: fs28fw700.copyWith( + color: Theme.of(context).extension()!.grey900!, ), ), Padding( padding: const EdgeInsets.only(left: 4.0), child: Text( '${locale.translate('cards.steps.steps')} ${_getDayName(touchedIndex)}', - style: dataVizCardTitleText.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), ), @@ -57,8 +57,8 @@ class StepsCardWidgetState extends State { children: [ Text( "${widget.model.currentMonth} ${widget.model.startOfWeek} - ${int.parse(widget.model.endOfWeek) < int.parse(widget.model.startOfWeek) ? widget.model.nextMonth : widget.model.currentMonth} ${widget.model.endOfWeek}, ${widget.model.currentYear}", - style: dataVizCardTitleText.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs12fw700.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), Spacer(), @@ -172,8 +172,8 @@ class StepsCardWidgetState extends State { value.toInt() % meta.appliedInterval == 0 ? value.toInt().toString() : '', - style: dataCardRightTitleStyle.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs14ls1.copyWith( + color: Theme.of(context).extension()!.grey600, ), ), ); diff --git a/lib/ui/cards/study_progress_card.dart b/lib/ui/cards/study_progress_card.dart index c74e4cf6..800b6b46 100644 --- a/lib/ui/cards/study_progress_card.dart +++ b/lib/ui/cards/study_progress_card.dart @@ -19,7 +19,7 @@ class StudyProgressCardWidgetState extends State { widget.model.updateProgress(); return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.white!, + backgroundColor: Theme.of(context).extension()!.white!, child: Padding( padding: const EdgeInsets.all(8.0), child: StreamBuilder( @@ -33,7 +33,7 @@ class StudyProgressCardWidgetState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text(locale.translate('cards.study_progress.title'), - style: dataCardTitleStyle), + style: fs16fw400ls1), ], ), ), diff --git a/lib/ui/cards/survey_card.dart b/lib/ui/cards/survey_card.dart index 92569b90..579b1b1f 100644 --- a/lib/ui/cards/survey_card.dart +++ b/lib/ui/cards/survey_card.dart @@ -21,7 +21,7 @@ class _SurveyCardState extends State { } return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.white!, + backgroundColor: Theme.of(context).extension()!.white!, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -30,7 +30,7 @@ class _SurveyCardState extends State { Padding( padding: const EdgeInsets.only(left: 10.0), child: Text(locale.translate('cards.survey.title').toUpperCase(), - style: dataCardTitleStyle), + style: fs16fw400ls1), ), SizedBox( height: 160, @@ -57,7 +57,7 @@ class _SurveyCardState extends State { ); Widget text = Text( '${entry.value} ${locale.translate(entry.key).truncateTo(12)}', - style: legendStyle, + style: fs12fw400, ); return Row( children: [ @@ -83,9 +83,10 @@ class _SurveyCardState extends State { ), Text( '$totalSurveys', - style: surveysCardTotalTextStyle.copyWith( - color: - Theme.of(context).extension()!.grey800, + style: fs24fw700.copyWith( + color: Theme.of(context) + .extension()! + .grey800, ), ) ], diff --git a/lib/ui/carp_study_style.dart b/lib/ui/carp_study_style.dart index 3d6f935f..0ac9bfce 100644 --- a/lib/ui/carp_study_style.dart +++ b/lib/ui/carp_study_style.dart @@ -1,8 +1,8 @@ part of carp_study_app; @immutable -class CarpColors extends ThemeExtension { - const CarpColors({ +class StudyAppColors extends ThemeExtension { + const StudyAppColors({ this.primary, this.warningColor, this.backgroundGray, @@ -44,7 +44,7 @@ class CarpColors extends ThemeExtension { final Color? grey950; @override - CarpColors copyWith( + StudyAppColors copyWith( {Color? primary, Color? warningColor, Color? backgroundGray, @@ -61,7 +61,7 @@ class CarpColors extends ThemeExtension { Color? grey800, Color? grey900, Color? grey950}) { - return CarpColors( + return StudyAppColors( primary: primary ?? this.primary, warningColor: warningColor ?? this.warningColor, backgroundGray: backgroundGray ?? this.backgroundGray, @@ -82,11 +82,11 @@ class CarpColors extends ThemeExtension { } @override - CarpColors lerp(CarpColors? other, double t) { - if (other is! CarpColors) { + StudyAppColors lerp(StudyAppColors? other, double t) { + if (other is! StudyAppColors) { return this; } - return CarpColors( + return StudyAppColors( primary: Color.lerp(primary, other.primary, t), warningColor: Color.lerp(warningColor, other.warningColor, t), backgroundGray: Color.lerp(backgroundGray, other.backgroundGray, t), @@ -109,7 +109,7 @@ class CarpColors extends ThemeExtension { ThemeData carpStudyTheme = ThemeData.light().copyWith( extensions: >[ - CarpColors( + StudyAppColors( primary: const Color(0xff000000), warningColor: Colors.orange[500], backgroundGray: const Color(0xfff2f2f7), @@ -179,7 +179,7 @@ ThemeData carpStudyTheme = ThemeData.light().copyWith( ThemeData carpStudyDarkTheme = ThemeData.dark().copyWith( extensions: >[ - CarpColors( + StudyAppColors( primary: const Color(0xff24B2FF), warningColor: Colors.orange[700], backgroundGray: const Color(0xff0e0e0e), @@ -253,13 +253,13 @@ ThemeData carpStudyDarkTheme = ThemeData.dark().copyWith( // These TextStyles are now implemented in ResearchPackage -// TextStyle studyTitleStyle = +// TextStyle fs24fw600 = // const TextStyle(fontSize: 24, fontWeight: FontWeight.w600); -// TextStyle studyDetailsInfoTitle = +// TextStyle fs16fw700 = // const TextStyle(fontSize: 16, fontWeight: FontWeight.w700); -// TextStyle studyDetailsInfoMessage = +// TextStyle fs12fw700 = // const TextStyle(fontSize: 12, fontWeight: FontWeight.w700); // TextStyle readMoreStudyStyle = @@ -278,29 +278,29 @@ ThemeData carpStudyDarkTheme = ThemeData.dark().copyWith( // TextStyle scoreTextStyle = // const TextStyle(fontSize: 12, fontWeight: FontWeight.w700); -// TextStyle aboutStudyCardTitleStyle = +// TextStyle fs24fw700 = // const TextStyle(fontSize: 24, fontWeight: FontWeight.w700) // .apply(fontFamily: 'OpenSans'); -// TextStyle aboutCardTitleStyle = +// TextStyle fs20fw700 = // const TextStyle(fontSize: 20, fontWeight: FontWeight.w700) // .apply(fontFamily: 'OpenSans'); // TextStyle aboutCardInfoStyle = // const TextStyle(fontSize: 14, fontStyle: FontStyle.italic); -// TextStyle aboutCardSubtitleStyle = +// TextStyle fs16fw600 = // const TextStyle(fontSize: 16, fontWeight: FontWeight.w600); -// TextStyle aboutCardContentStyle = +// TextStyle fs16fw400 = // const TextStyle(fontSize: 16, fontWeight: FontWeight.w400) // .apply(fontFamily: 'OpenSans'); -// TextStyle aboutCardTimeAgoStyle = +// TextStyle fs10fw600 = // const TextStyle(fontSize: 10, fontWeight: FontWeight.w600) // .apply(fontFamily: 'OpenSans'); -// TextStyle sectionTitleStyle = +// TextStyle fs18fw700 = // const TextStyle(fontSize: 18, fontWeight: FontWeight.w700); // TextStyle inputFieldStyle = @@ -312,18 +312,18 @@ ThemeData carpStudyDarkTheme = ThemeData.dark().copyWith( // TextStyle studyDescriptionStyle = // const TextStyle(fontSize: 12, fontWeight: FontWeight.w300); -// TextStyle dataCardTitleStyle = const TextStyle( +// TextStyle fs16fw400ls1 = const TextStyle( // fontSize: 16, fontWeight: FontWeight.w400, letterSpacing: 1); // TextStyle dataCardRightTitleStyle = // const TextStyle(fontSize: 14, letterSpacing: 1); // TextStyle measuresStyle = // const TextStyle(fontSize: 18, fontWeight: FontWeight.w400); -// TextStyle legendStyle = +// TextStyle fs12fw400 = // const TextStyle(fontSize: 12, fontWeight: FontWeight.w400); -// TextStyle audioTitleStyle = +// TextStyle fs22fw700 = // const TextStyle(fontSize: 22, fontWeight: FontWeight.w700); -// TextStyle audioContentStyle = +// TextStyle fs16fw600 = // const TextStyle(fontSize: 16, fontWeight: FontWeight.w700); // TextStyle heartRateNumberStyle = @@ -343,27 +343,27 @@ ThemeData carpStudyDarkTheme = ThemeData.dark().copyWith( // TextStyle dataVizCardBottomText = // const TextStyle(fontSize: 12, fontWeight: FontWeight.w700); -// TextStyle deviceTitle = +// TextStyle fs16fw700 = // const TextStyle(fontSize: 16, fontWeight: FontWeight.w700); -// TextStyle deviceSubtitle = +// TextStyle fs12fw700 = // const TextStyle(fontSize: 12, fontWeight: FontWeight.w700); // TextStyle healthServiceConnectTitleStyle = // const TextStyle(fontSize: 24, fontWeight: FontWeight.w700); -// TextStyle healthServiceConnectMessageStyle = +// TextStyle fs22fw700 = // const TextStyle(fontSize: 22, fontWeight: FontWeight.w700); -// TextStyle profileSectionStyle = +// TextStyle fs12fw600 = // TextStyle(fontSize: 12, fontWeight: FontWeight.w600); -// TextStyle profileTitleStyle = +// TextStyle fs14fw600 = // TextStyle(fontSize: 14, fontWeight: FontWeight.w600); -// TextStyle profileActionStyle = +// TextStyle fs16fw600 = // TextStyle(fontSize: 16, fontWeight: FontWeight.w600); // TextStyle timerStyle = // const TextStyle(fontSize: 36, fontWeight: FontWeight.w600); -// TextStyle studyNameStyle = +// TextStyle fs30fw800 = // const TextStyle(fontSize: 30.0, fontWeight: FontWeight.w800); diff --git a/lib/ui/pages/data_visualization_page.dart b/lib/ui/pages/data_visualization_page.dart index 56db1a91..373b3ca6 100644 --- a/lib/ui/pages/data_visualization_page.dart +++ b/lib/ui/pages/data_visualization_page.dart @@ -16,7 +16,7 @@ class _DataVisualizationPageState extends State { RPLocalizations locale = RPLocalizations.of(context)!; return Scaffold( backgroundColor: - Theme.of(context).extension()!.backgroundGray, + Theme.of(context).extension()!.backgroundGray, body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -38,9 +38,9 @@ class _DataVisualizationPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(locale.translate('pages.data_viz.title'), - style: aboutStudyCardTitleStyle.copyWith( + style: fs24fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900, fontWeight: FontWeight.bold, )), @@ -60,9 +60,9 @@ class _DataVisualizationPageState extends State { padding: const EdgeInsets.symmetric( horizontal: 15, vertical: 24.0), child: Text(locale.translate('pages.data_viz.thanks'), - style: aboutCardSubtitleStyle.copyWith( + style: fs16fw600.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey600, )), ), diff --git a/lib/ui/pages/device_list_page.dart b/lib/ui/pages/device_list_page.dart index d392f148..9e563688 100644 --- a/lib/ui/pages/device_list_page.dart +++ b/lib/ui/pages/device_list_page.dart @@ -49,7 +49,8 @@ class DeviceListPageState extends State { Widget build(BuildContext context) { RPLocalizations locale = RPLocalizations.of(context)!; return Scaffold( - backgroundColor: Theme.of(context).extension()!.backgroundGray, + backgroundColor: + Theme.of(context).extension()!.backgroundGray, body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -72,9 +73,10 @@ class DeviceListPageState extends State { children: [ Text( locale.translate('pages.devices.title'), - style: aboutStudyCardTitleStyle.copyWith( - color: - Theme.of(context).extension()!.grey900, + style: fs24fw700.copyWith( + color: Theme.of(context) + .extension()! + .grey900, fontWeight: FontWeight.bold, ), ), @@ -94,9 +96,9 @@ class DeviceListPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(locale.translate("pages.devices.message"), - style: aboutCardSubtitleStyle.copyWith( + style: fs16fw600.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey600, )), const SizedBox(height: 15), @@ -134,7 +136,7 @@ class DeviceListPageState extends State { builder: (BuildContext context, Widget? widget) => Center( child: StudiesMaterial( backgroundColor: - Theme.of(context).extension()!.grey50!, + Theme.of(context).extension()!.grey50!, child: _cardListBuilder( leading: _smartphoneDevice[index].icon!, title: ( @@ -182,8 +184,7 @@ class DeviceListPageState extends State { child: Text( locale.translate( device.getDeviceStatusIcon as String), - style: aboutCardTitleStyle.copyWith( - color: Colors.white)), + style: fs20fw700.copyWith(color: Colors.white)), ), ), ); @@ -218,8 +219,7 @@ class DeviceListPageState extends State { child: Text( locale.translate( service.getServiceStatusIcon as String), - style: aboutCardTitleStyle.copyWith( - color: Colors.white), + style: fs20fw700.copyWith(color: Colors.white), ), ) : service.getServiceStatusIcon as Icon, @@ -255,8 +255,8 @@ class DeviceListPageState extends State { children: [ Text( title!.$1, - style: deviceTitle.copyWith( - color: Theme.of(context).extension()!.grey900, + style: fs16fw700.copyWith( + color: Theme.of(context).extension()!.grey900, ), ), SizedBox(width: 6), @@ -275,8 +275,9 @@ class DeviceListPageState extends State { alignment: Alignment.centerLeft, child: Text( subtitle, - style: deviceSubtitle.copyWith( - color: Theme.of(context).extension()!.grey700, + style: fs12fw700.copyWith( + color: + Theme.of(context).extension()!.grey700, ), ), ), @@ -300,7 +301,7 @@ class DeviceListPageState extends State { ) => Center( child: StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.grey50!, + backgroundColor: Theme.of(context).extension()!.grey50!, child: StreamBuilder( stream: stream, initialData: initialData, @@ -320,7 +321,7 @@ class DeviceListPageState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => HealthServiceConnectPage1()), + builder: (context) => HealthServiceConnectPage()), ); } else { await service.deviceManager.requestPermissions(); @@ -356,7 +357,7 @@ class DeviceListPageState extends State { if (disconnect) await device.disconnectFromDevice(); } else { final hasSeenInstructions = - LocalSettings().hasSeenConnectionInstructions; + LocalSettings().hasSeenBluetoothConnectionInstructions; Navigator.push( context, MaterialPageRoute( diff --git a/lib/ui/pages/devices_page.authorization_dialog.dart b/lib/ui/pages/devices_page.authorization_dialog.dart index ec22957e..f7a6f370 100644 --- a/lib/ui/pages/devices_page.authorization_dialog.dart +++ b/lib/ui/pages/devices_page.authorization_dialog.dart @@ -32,7 +32,7 @@ class AuthorizationDialog extends StatelessWidget { Text( locale.translate( "pages.devices.connection.bluetooth_authorization.message"), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), Image( diff --git a/lib/ui/pages/devices_page.bluetooth_connection_page.dart b/lib/ui/pages/devices_page.bluetooth_connection_page.dart index 9d952dfc..0d0be9e1 100644 --- a/lib/ui/pages/devices_page.bluetooth_connection_page.dart +++ b/lib/ui/pages/devices_page.bluetooth_connection_page.dart @@ -41,16 +41,21 @@ class _BluetoothConnectionPageState extends State { BluetoothDevice? selectedDevice; int selected = 40; + /// Set of normalized UUIDs (no dashes, lower-case) to filter discovered devices by + /// If empty, no UUID filtering is applied. + final Set _filterUuids = {}; + @override Widget build(BuildContext context) { RPLocalizations locale = RPLocalizations.of(context)!; return Scaffold( + backgroundColor: + Theme.of(context).extension()!.backgroundGray, body: SafeArea( child: Stack( children: [ Container( - color: Theme.of(context).colorScheme.secondary, child: Column( children: [ Padding( @@ -120,7 +125,7 @@ class _BluetoothConnectionPageState extends State { Flexible( child: Text( stepTitleMap[currentStep] ?? '', - style: healthServiceConnectMessageStyle.copyWith( + style: fs22fw700.copyWith( color: Theme.of(context).primaryColor, ), textAlign: TextAlign.center, @@ -165,7 +170,7 @@ class _BluetoothConnectionPageState extends State { _connectDevice(), selectedDevice != null, ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).extension()!.primary, + backgroundColor: Theme.of(context).extension()!.primary, padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12), ), TextStyle( @@ -186,7 +191,7 @@ class _BluetoothConnectionPageState extends State { }, true, ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).extension()!.primary, + backgroundColor: Theme.of(context).extension()!.primary, padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12), ), TextStyle( @@ -206,7 +211,7 @@ class _BluetoothConnectionPageState extends State { }, true, ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).extension()!.primary, + backgroundColor: Theme.of(context).extension()!.primary, padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12), ), TextStyle( @@ -305,41 +310,55 @@ class _BluetoothConnectionPageState extends State { "${locale.translate("pages.devices.connection.step.scan.1")} " "${locale.translate(device.typeName)} " "${locale.translate("pages.devices.connection.step.scan.2")}", - style: healthServiceConnectMessageStyle, + style: fs22fw700, textAlign: TextAlign.justify, ), Expanded( child: StreamBuilder>( stream: FlutterBluePlus.scanResults, initialData: const [], - builder: (context, snapshot) => SingleChildScrollView( - padding: const EdgeInsets.only(top: 16), - child: Column( - children: snapshot.data! - .where( - (element) => element.device.platformName.isNotEmpty) - .toList() - .asMap() - .entries - .map( - (bluetoothDevice) => ListTile( - selected: bluetoothDevice.key == selected, - title: Text( - bluetoothDevice.value.device.platformName, - style: healthServiceConnectMessageStyle, + builder: (context, snapshot) => Scrollbar( + thumbVisibility: true, + child: SingleChildScrollView( + padding: const EdgeInsets.only(top: 16), + child: Column( + children: snapshot.data! + .where((element) => + element.device.platformName.isNotEmpty && + _matchesUuid(element, _filterUuids)) + .toList() + .asMap() + .entries + .map( + (bluetoothDevice) => StudiesMaterial( + // hasBorder: true, + backgroundColor: Theme.of(context) + .extension()! + .grey50!, + child: InkWell( + child: ListTile( + selected: bluetoothDevice.key == selected, + title: Text( + bluetoothDevice.value.device.platformName, + style: fs22fw700.copyWith( + fontSize: 20, + ), + ), + selectedTileColor: Theme.of(context) + .primaryColor + .withValues(alpha: 0.2), + ), + onTap: () { + selectedDevice = bluetoothDevice.value.device; + setState(() { + selected = bluetoothDevice.key; + }); + }, + ), ), - selectedTileColor: Theme.of(context) - .primaryColor - .withValues(alpha: 0.2), - onTap: () { - selectedDevice = bluetoothDevice.value.device; - setState(() { - selected = bluetoothDevice.key; - }); - }, - ), - ) - .toList(), + ) + .toList(), + ), ), ), ), @@ -357,7 +376,7 @@ class _BluetoothConnectionPageState extends State { text: locale .translate("pages.devices.connection.instructions"), style: TextStyle( - color: Theme.of(context).extension()!.primary, + color: Theme.of(context).extension()!.primary, decoration: TextDecoration.underline, fontWeight: FontWeight.bold, ), @@ -373,8 +392,8 @@ class _BluetoothConnectionPageState extends State { ), ], ), - style: healthServiceConnectMessageStyle.copyWith( - color: Theme.of(context).extension()!.grey900), + style: fs22fw700.copyWith( + color: Theme.of(context).extension()!.grey900), textAlign: TextAlign.center, ), ) @@ -383,6 +402,34 @@ class _BluetoothConnectionPageState extends State { ); } + /// Returns true if [scanResult] advertises any UUID present in [filterUuids]. + /// If [filterUuids] is empty, always returns true. + bool _matchesUuid(ScanResult scanResult, Set filterUuids) { + if (filterUuids.isEmpty) return true; + + // Normalize helper: remove dashes and lowercase + String normalize(String u) => u.replaceAll('-', '').toLowerCase(); + + try { + // FlutterBluePlus ScanResult contains advertisementData with serviceUuids + final adv = scanResult.advertisementData; + final serviceUuids = adv.serviceUuids; + for (var u in serviceUuids) { + final us = u.toString(); + if (filterUuids.contains(normalize(us))) return true; + } + + // Also check device id (remoteId) as fallback + final devId = scanResult.device.remoteId.str; + if (filterUuids.contains(normalize(devId))) return true; + } catch (_) { + // If structure differs, fall back to allowing the device + return true; + } + + return false; + } + Widget connectionInstructions(DeviceViewModel device, BuildContext context) { RPLocalizations locale = RPLocalizations.of(context)!; AssetImage? assetImage; @@ -420,8 +467,8 @@ class _BluetoothConnectionPageState extends State { Image connectionImage = Image( image: assetImage, - width: MediaQuery.of(context).size.height * 0.5, - height: MediaQuery.of(context).size.height * 0.5, + width: MediaQuery.of(context).size.height * 0.3, + height: MediaQuery.of(context).size.height * 0.3, ); return Column( children: [ @@ -436,7 +483,7 @@ class _BluetoothConnectionPageState extends State { padding: const EdgeInsets.only(bottom: 20.0), child: Text( locale.translate(device.connectionInstructions!), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), ), @@ -467,7 +514,7 @@ class _BluetoothConnectionPageState extends State { child: Text( ("${locale.translate("pages.devices.connection.step.confirm.1")} '${device?.platformName}' ${locale.translate("pages.devices.connection.step.confirm.2")}") .trim(), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), ), diff --git a/lib/ui/pages/devices_page.disconnection_dialog.dart b/lib/ui/pages/devices_page.disconnection_dialog.dart index a1326908..0390df0e 100644 --- a/lib/ui/pages/devices_page.disconnection_dialog.dart +++ b/lib/ui/pages/devices_page.disconnection_dialog.dart @@ -26,7 +26,7 @@ class DisconnectionDialog extends StatelessWidget { children: [ Text( "${locale.translate("pages.devices.connection.disconnect_bluetooth.message")} ${locale.translate(device.name)}?", - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), Row( diff --git a/lib/ui/pages/devices_page.enable_bluetooth_dialog.dart b/lib/ui/pages/devices_page.enable_bluetooth_dialog.dart index 7c6d3aa6..72944dfc 100644 --- a/lib/ui/pages/devices_page.enable_bluetooth_dialog.dart +++ b/lib/ui/pages/devices_page.enable_bluetooth_dialog.dart @@ -31,7 +31,7 @@ class EnableBluetoothDialog extends StatelessWidget { Text( locale.translate( "pages.devices.connection.enable_bluetooth.message1"), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), Padding( @@ -40,7 +40,7 @@ class EnableBluetoothDialog extends StatelessWidget { Text( locale.translate( "pages.devices.connection.enable_bluetooth.message2"), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), if (Platform.isAndroid || Platform.isIOS) @@ -54,7 +54,7 @@ class EnableBluetoothDialog extends StatelessWidget { Text( locale.translate( "pages.devices.connection.enable_bluetooth.message3"), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), ], diff --git a/lib/ui/pages/devices_page.health_service_connect2.dart b/lib/ui/pages/devices_page.health_service_connect.dart similarity index 52% rename from lib/ui/pages/devices_page.health_service_connect2.dart rename to lib/ui/pages/devices_page.health_service_connect.dart index 9d79643d..0a35387b 100644 --- a/lib/ui/pages/devices_page.health_service_connect2.dart +++ b/lib/ui/pages/devices_page.health_service_connect.dart @@ -1,7 +1,7 @@ part of carp_study_app; -class HealthServiceConnectPage2 extends StatelessWidget { - const HealthServiceConnectPage2({super.key}); +class HealthServiceConnectPage extends StatelessWidget { + const HealthServiceConnectPage({super.key}); @override Widget build(BuildContext context) { @@ -14,15 +14,15 @@ class HealthServiceConnectPage2 extends StatelessWidget { .first; return Scaffold( + backgroundColor: Theme.of(context).extension()!.grey100, body: SafeArea( child: Container( - color: Theme.of(context).colorScheme.secondary, child: Column( children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 18), - child: const CarpAppBar(hasProfileIcon: true), + child: const CarpAppBar(), ), Expanded( child: Padding( @@ -30,25 +30,15 @@ class HealthServiceConnectPage2 extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(20), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.1), - blurRadius: 10, - spreadRadius: 2, - ), - ], - ), - child: Image.asset( - Platform.isAndroid - ? 'assets/instructions/google_health_connect_icon.png' - : 'assets/instructions/apple_health_icon.png', - height: 250, - width: 250, + Expanded( + child: Center( + child: Image.asset( + Platform.isAndroid + ? 'assets/instructions/google_health_connect_preview.png' + : 'assets/instructions/apple_health_preview.png', + fit: BoxFit.contain, + width: double.infinity, + ), ), ), const SizedBox(height: 20), @@ -58,36 +48,36 @@ class HealthServiceConnectPage2 extends StatelessWidget { TextSpan( text: "${locale.translate("pages.devices.type.health.instructions.page2.part1")} ", - style: healthServiceConnectMessageStyle.copyWith( + style: fs22fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900, ), ), TextSpan( text: "${Platform.isAndroid ? locale.translate("pages.devices.type.health.instructions.page2.android.allow_all") : locale.translate("pages.devices.type.health.instructions.page2.ios.turn_on_all")} ", - style: healthServiceConnectMessageStyle.copyWith( + style: fs22fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .primary, // Change to desired color ), ), TextSpan( text: "${locale.translate("pages.devices.type.health.instructions.page2.part2")} ", - style: healthServiceConnectMessageStyle.copyWith( + style: fs22fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900, ), ), TextSpan( text: "${locale.translate("pages.devices.type.health.instructions.page2.allow")} ", - style: healthServiceConnectMessageStyle.copyWith( + style: fs22fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .primary, // Change to desired color ), ), @@ -97,9 +87,9 @@ class HealthServiceConnectPage2 extends StatelessWidget { "pages.devices.type.health.instructions.page2.part3.android") : locale.translate( "pages.devices.type.health.instructions.page2.part3.ios"), - style: healthServiceConnectMessageStyle.copyWith( + style: fs22fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900, ), ), @@ -108,39 +98,6 @@ class HealthServiceConnectPage2 extends StatelessWidget { textAlign: TextAlign.center, ), const SizedBox(height: 30), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - OutlinedButton( - child: const Text("Cancel"), - onPressed: () { - Navigator.pop(context); - }, - ), - ElevatedButton( - child: const Text( - "Next", - style: TextStyle( - color: Colors.white, - ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context) - .extension()! - .primary, - padding: const EdgeInsets.symmetric( - horizontal: 30, vertical: 12), - ), - onPressed: () async { - await healthServive.deviceManager - .requestPermissions(); - await healthServive.deviceManager.connect(); - - Navigator.pop(context); - }, - ), - ], - ), ], ), ), @@ -149,6 +106,40 @@ class HealthServiceConnectPage2 extends StatelessWidget { ), ), ), + bottomNavigationBar: Padding( + padding: const EdgeInsets.symmetric(vertical: 26), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + OutlinedButton( + child: const Text("Cancel"), + onPressed: () { + Navigator.pop(context); + }, + ), + ElevatedButton( + child: const Text( + "Next", + style: TextStyle( + color: Colors.white, + ), + ), + style: ElevatedButton.styleFrom( + backgroundColor: + Theme.of(context).extension()!.primary, + padding: + const EdgeInsets.symmetric(horizontal: 30, vertical: 12), + ), + onPressed: () async { + await healthServive.deviceManager.requestPermissions(); + await healthServive.deviceManager.connect(); + + Navigator.pop(context); + }, + ), + ], + ), + ), ); } } diff --git a/lib/ui/pages/devices_page.health_service_connect1.dart b/lib/ui/pages/devices_page.health_service_connect1.dart deleted file mode 100644 index 70f358e8..00000000 --- a/lib/ui/pages/devices_page.health_service_connect1.dart +++ /dev/null @@ -1,116 +0,0 @@ -part of carp_study_app; - -class HealthServiceConnectPage1 extends StatelessWidget { - const HealthServiceConnectPage1({super.key}); - - @override - Widget build(BuildContext context) { - RPLocalizations locale = RPLocalizations.of(context)!; - return Scaffold( - body: SafeArea( - child: Container( - color: Theme.of(context).colorScheme.secondary, - child: Column( - children: [ - Padding( - padding: - const EdgeInsets.symmetric(vertical: 8.0, horizontal: 18), - child: const CarpAppBar(hasProfileIcon: true), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(20), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.1), - blurRadius: 10, - spreadRadius: 2, - ), - ], - ), - child: Image.asset( - Platform.isAndroid - ? 'assets/instructions/google_health_connect_icon.png' - : 'assets/instructions/apple_health_icon.png', - height: 250, - width: 250, - ), - ), - const SizedBox(height: 20), - Text( - Platform.isAndroid - ? locale.translate( - "pages.devices.type.health.instructions.page1.android") - : locale.translate( - "pages.devices.type.health.instructions.page1.ios"), - style: healthServiceConnectTitleStyle.copyWith( - color: Theme.of(context) - .extension()! - .primary), - textAlign: TextAlign.center, - ), - const SizedBox(height: 10), - Text( - "${locale.translate("pages.devices.type.health.instructions.page1.part1")} " - "${Platform.isAndroid ? locale.translate("pages.devices.type.health.instructions.page1.android") : locale.translate("pages.devices.type.health.instructions.page1.ios")} " - "${locale.translate("pages.devices.type.health.instructions.page1.part2")}", - style: healthServiceConnectMessageStyle.copyWith( - color: Theme.of(context) - .extension()! - .grey900), - textAlign: TextAlign.center, - ), - const SizedBox(height: 30), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - OutlinedButton( - child: const Text("Cancel"), - onPressed: () { - Navigator.pop(context); - }, - ), - ElevatedButton( - child: Text( - locale.translate("Next"), - style: TextStyle( - color: Colors.white, - ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context) - .extension()! - .primary, - padding: const EdgeInsets.symmetric( - horizontal: 30, vertical: 12), - ), - onPressed: () { - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => - HealthServiceConnectPage2()), - ); - }, - ), - ], - ), - ], - ), - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/lib/ui/pages/devices_page.list_title.dart b/lib/ui/pages/devices_page.list_title.dart index 339c4c7f..19f57309 100644 --- a/lib/ui/pages/devices_page.list_title.dart +++ b/lib/ui/pages/devices_page.list_title.dart @@ -23,8 +23,8 @@ class DevicesPageListTitle extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 6), child: Text( locale.translate("pages.devices.${type.name}.title").toUpperCase(), - style: dataCardTitleStyle.copyWith( - color: Theme.of(context).extension()!.grey900, + style: fs16fw400ls1.copyWith( + color: Theme.of(context).extension()!.grey900, fontWeight: FontWeight.bold)), ), ); diff --git a/lib/ui/pages/enable_connection_dialog.dart b/lib/ui/pages/enable_connection_dialog.dart index 5ebb653d..cf5c7776 100644 --- a/lib/ui/pages/enable_connection_dialog.dart +++ b/lib/ui/pages/enable_connection_dialog.dart @@ -37,7 +37,7 @@ class EnableInternetConnectionDialog extends StatelessWidget { Text( locale.translate( "pages.login.internet_connection.enable_internet_connections.general_message"), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), Padding( @@ -45,7 +45,7 @@ class EnableInternetConnectionDialog extends StatelessWidget { child: Text( locale.translate( "pages.login.internet_connection.enable_internet_connections.wifi_message"), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, )), Padding( @@ -60,7 +60,7 @@ class EnableInternetConnectionDialog extends StatelessWidget { child: Text( locale.translate( "pages.login.internet_connection.enable_internet_connections.mobile_data_message"), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), ), @@ -111,7 +111,7 @@ class EnableInternetConnectionDialog extends StatelessWidget { Text( locale.translate( "pages.login.internet_connection.enable_internet_connections.general_message"), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), Padding( @@ -119,7 +119,7 @@ class EnableInternetConnectionDialog extends StatelessWidget { child: Text( locale.translate( "pages.login.internet_connection.enable_internet_connections.wifi_message"), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, )), Padding( @@ -135,7 +135,7 @@ class EnableInternetConnectionDialog extends StatelessWidget { Text( locale.translate( "pages.login.internet_connection.enable_internet_connections.mobile_data_message"), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), ]), diff --git a/lib/ui/pages/home_page.dart b/lib/ui/pages/home_page.dart index aa6aacc8..791a9920 100644 --- a/lib/ui/pages/home_page.dart +++ b/lib/ui/pages/home_page.dart @@ -96,19 +96,22 @@ class HomePageState extends State { AppTaskController().userTaskEvents.listen((userTask) { if (userTask.state == UserTaskState.notified) { userTask.onStart(); - if (userTask.hasWidget) context.push('/task/${userTask.id}'); + if (userTask.hasWidget) { + _rootNavigatorKey.currentContext?.push('/task/${userTask.id}'); + } } }); return Scaffold( - backgroundColor: Theme.of(context).extension()!.backgroundGray, + backgroundColor: + Theme.of(context).extension()!.backgroundGray, body: SafeArea( child: widget.child, ), bottomNavigationBar: BottomNavigationBar( - backgroundColor: Theme.of(context).extension()!.white, + backgroundColor: Theme.of(context).extension()!.white, type: BottomNavigationBarType.fixed, - selectedItemColor: Theme.of(context).extension()!.primary, + selectedItemColor: Theme.of(context).extension()!.primary, //unselectedItemColor: Theme.of(context).primaryColor.withOpacity(0.8), items: [ BottomNavigationBarItem( diff --git a/lib/ui/pages/home_page.install_health_connect_dialog.dart b/lib/ui/pages/home_page.install_health_connect_dialog.dart index 2a60a0cf..2129ece0 100644 --- a/lib/ui/pages/home_page.install_health_connect_dialog.dart +++ b/lib/ui/pages/home_page.install_health_connect_dialog.dart @@ -14,7 +14,7 @@ class InstallHealthConnectDialog extends StatelessWidget { ), content: Text( locale.translate('pages.about.install_health_connect.description'), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), actions: [ diff --git a/lib/ui/pages/invitation_list_page.dart b/lib/ui/pages/invitation_list_page.dart index 0180d634..d6ddbadb 100644 --- a/lib/ui/pages/invitation_list_page.dart +++ b/lib/ui/pages/invitation_list_page.dart @@ -9,7 +9,8 @@ class InvitationListPage extends StatelessWidget { Widget build(BuildContext context) { RPLocalizations locale = RPLocalizations.of(context)!; return Scaffold( - backgroundColor: Theme.of(context).extension()!.backgroundGray, + backgroundColor: + Theme.of(context).extension()!.backgroundGray, body: FutureBuilder>( future: bloc.backend.getInvitations(), builder: (context, snapshot) { @@ -38,7 +39,7 @@ class InvitationListPage extends StatelessWidget { slivers: [ SliverAppBar( backgroundColor: - Theme.of(context).extension()!.backgroundGray, + Theme.of(context).extension()!.backgroundGray, title: const CarpAppBar(), centerTitle: true, pinned: true, @@ -121,7 +122,7 @@ class InvitationMaterial extends StatelessWidget { Widget build(BuildContext context) { RPLocalizations locale = RPLocalizations.of(context)!; return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.white!, + backgroundColor: Theme.of(context).extension()!.white!, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), ), @@ -138,7 +139,7 @@ class InvitationMaterial extends StatelessWidget { Text( invitation.invitation.name, maxLines: 1, - style: studyTitleStyle.copyWith( + style: fs24fw600.copyWith( color: CACHET.TASK_COMPLETED_BLUE, overflow: TextOverflow.ellipsis), ), @@ -148,15 +149,17 @@ class InvitationMaterial extends StatelessWidget { TextSpan( text: locale.translate( 'invitation_list.roles_in_the_study.description'), - style: studyDetailsInfoTitle.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs16fw700.copyWith( + color: + Theme.of(context).extension()!.grey600, fontSize: 12, ), ), TextSpan( text: invitation.participantRoleName, - style: studyDetailsInfoTitle.copyWith( - color: Theme.of(context).extension()!.grey600, + style: fs16fw700.copyWith( + color: + Theme.of(context).extension()!.grey600, fontSize: 12, ), ), @@ -166,8 +169,8 @@ class InvitationMaterial extends StatelessWidget { Text( invitation.invitation.description ?? '', maxLines: 2, - style: studyDetailsInfoTitle.copyWith( - color: Theme.of(context).extension()!.grey900, + style: fs16fw700.copyWith( + color: Theme.of(context).extension()!.grey900, overflow: TextOverflow.ellipsis, ), ), diff --git a/lib/ui/pages/invitation_page.dart b/lib/ui/pages/invitation_page.dart index 76199656..c7084b18 100644 --- a/lib/ui/pages/invitation_page.dart +++ b/lib/ui/pages/invitation_page.dart @@ -17,7 +17,8 @@ class InvitationDetailsPage extends StatelessWidget { var invitation = model.getInvitation(invitationId); return Scaffold( - backgroundColor: Theme.of(context).extension()!.backgroundGray, + backgroundColor: + Theme.of(context).extension()!.backgroundGray, body: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: SafeArea( @@ -59,7 +60,7 @@ class InvitationDetailsPage extends StatelessWidget { padding: const EdgeInsets.only(top: 16.0), child: StudiesMaterial( backgroundColor: - Theme.of(context).extension()!.white!, + Theme.of(context).extension()!.white!, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), ), @@ -93,7 +94,7 @@ class InvitationDetailsPage extends StatelessWidget { padding: const EdgeInsets.only(top: 16.0), child: StudiesMaterial( backgroundColor: - Theme.of(context).extension()!.white!, + Theme.of(context).extension()!.white!, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), ), @@ -118,7 +119,7 @@ class InvitationDetailsPage extends StatelessWidget { fontWeight: FontWeight.bold, fontSize: 22.0, color: Theme.of(context) - .extension()! + .extension()! .primary, ), ), @@ -133,7 +134,7 @@ class InvitationDetailsPage extends StatelessWidget { fontWeight: FontWeight.bold, fontSize: 14, color: Theme.of(context) - .extension()! + .extension()! .grey600, ), maxLines: 1, diff --git a/lib/ui/pages/message_details_page.dart b/lib/ui/pages/message_details_page.dart index 93817864..757cf560 100644 --- a/lib/ui/pages/message_details_page.dart +++ b/lib/ui/pages/message_details_page.dart @@ -42,7 +42,7 @@ class MessageDetailsPage extends StatelessWidget { left: 26, right: 10, top: 16, bottom: 16), icon: Icon( Icons.arrow_back_ios, - color: Theme.of(context).extension()!.grey600, + color: Theme.of(context).extension()!.grey600, ), onPressed: () { if (context.canPop()) { @@ -52,19 +52,31 @@ class MessageDetailsPage extends StatelessWidget { } }, ), - Material( - color: CACHET.DEPLOYMENT_DEPLOYING, - borderRadius: BorderRadius.circular(100.0), - child: Padding( - padding: const EdgeInsets.all(12.0), - child: Text( - locale.translate(message.type - .toString() - .split('.') - .last - .toLowerCase()), - style: aboutCardSubtitleStyle.copyWith( - color: Colors.white)), + Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: Text(locale.translate(message.title!), + style: fs20fw700.copyWith( + color: Theme.of(context) + .extension()! + .grey900)), + ), + Spacer(), + Padding( + padding: const EdgeInsets.only(right: 24), + child: Material( + color: CACHET.DEPLOYMENT_DEPLOYING, + borderRadius: BorderRadius.circular(100.0), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12.0, vertical: 6.0), + child: Text( + locale.translate(message.type + .toString() + .split('.') + .last + .toLowerCase()), + style: fs16fw600.copyWith(color: Colors.white)), + ), ), ), ], @@ -74,22 +86,14 @@ class MessageDetailsPage extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), - child: Text(locale.translate(message.title!), - style: aboutCardTitleStyle.copyWith( - color: Theme.of(context) - .extension()! - .grey900)), - ), message.subTitle != null ? Padding( padding: const EdgeInsets.symmetric( horizontal: 10.0, vertical: 6.0), child: Text(locale.translate(message.subTitle!), - style: aboutCardContentStyle.copyWith( + style: fs16fw400.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey700)), ) : const SizedBox.shrink(), @@ -118,9 +122,9 @@ class MessageDetailsPage extends StatelessWidget { if (message.message != null) Text( locale.translate(message.message!), - style: aboutCardContentStyle.copyWith( + style: fs16fw400.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900), textAlign: TextAlign.justify, ) diff --git a/lib/ui/pages/process_message_page.dart b/lib/ui/pages/process_message_page.dart index df00b325..d9b4b131 100644 --- a/lib/ui/pages/process_message_page.dart +++ b/lib/ui/pages/process_message_page.dart @@ -70,11 +70,9 @@ class ProcessMessagePage extends StatelessWidget { const SizedBox(height: 40), messageImage(), const SizedBox(height: 20), - Center( - child: - Text(locale.translate(title), style: audioTitleStyle)), + Center(child: Text(locale.translate(title), style: fs22fw700)), const SizedBox(height: 10), - Text(locale.translate(description), style: audioContentStyle), + Text(locale.translate(description), style: fs16fw600), ]), ), bottomSheet: Row( diff --git a/lib/ui/pages/profile_page.dart b/lib/ui/pages/profile_page.dart index 14e53592..4b390de4 100644 --- a/lib/ui/pages/profile_page.dart +++ b/lib/ui/pages/profile_page.dart @@ -26,7 +26,7 @@ class ProfilePageState extends State { RPLocalizations locale = RPLocalizations.of(context)!; return Scaffold( - backgroundColor: Theme.of(context).extension()!.grey100, + backgroundColor: Theme.of(context).extension()!.grey100, body: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, @@ -43,7 +43,7 @@ class ProfilePageState extends State { icon: Icon(Icons.account_circle, color: Theme.of(context).primaryColor, size: 30), label: Text(locale.translate("pages.profile.title"), - style: aboutCardTitleStyle.copyWith( + style: fs20fw700.copyWith( color: Theme.of(context).primaryColor)), ), IconButton( @@ -215,7 +215,7 @@ class ProfilePageState extends State { Widget _buildSectionCard(BuildContext context, List children) { return Card( - color: Theme.of(context).extension()!.grey50, + color: Theme.of(context).extension()!.grey50, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), @@ -225,7 +225,7 @@ class ProfilePageState extends State { children: ListTile.divideTiles( context: context, tiles: children, - color: Theme.of(context).extension()!.grey400, + color: Theme.of(context).extension()!.grey400, ).toList(), ), ), @@ -234,14 +234,13 @@ class ProfilePageState extends State { Widget _buildListTile(String title, String subtitle) { return ListTile( - title: Text(title, - style: profileSectionStyle.copyWith(color: CACHET.GREY_6)), + title: Text(title, style: fs12fw600.copyWith(color: CACHET.GREY_6)), subtitle: FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.centerLeft, child: Text( subtitle, - style: profileTitleStyle, + style: fs14fw600, maxLines: 1, ), ), @@ -258,8 +257,8 @@ class ProfilePageState extends State { return ListTile( leading: leading, title: Text(title, - style: profileActionStyle.copyWith( - color: Theme.of(context).extension()!.grey900)), + style: fs16fw600.copyWith( + color: Theme.of(context).extension()!.grey900)), trailing: trailing, onTap: onTap, contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 16), diff --git a/lib/ui/pages/study_details_page.dart b/lib/ui/pages/study_details_page.dart index b4a6102b..6f1673fc 100644 --- a/lib/ui/pages/study_details_page.dart +++ b/lib/ui/pages/study_details_page.dart @@ -10,10 +10,11 @@ class StudyDetailsPage extends StatelessWidget { RPLocalizations locale = RPLocalizations.of(context)!; return Scaffold( - backgroundColor: Theme.of(context).extension()!.backgroundGray, + backgroundColor: + Theme.of(context).extension()!.backgroundGray, body: SafeArea( child: Container( - color: Theme.of(context).extension()!.backgroundGray, + color: Theme.of(context).extension()!.backgroundGray, child: Column( children: [ Padding( @@ -28,7 +29,7 @@ class StudyDetailsPage extends StatelessWidget { left: 26, right: 10, top: 16, bottom: 16), icon: Icon( Icons.arrow_back_ios, - color: Theme.of(context).extension()!.grey600, + color: Theme.of(context).extension()!.grey600, ), onPressed: () { if (context.canPop()) { @@ -41,9 +42,9 @@ class StudyDetailsPage extends StatelessWidget { Padding( padding: const EdgeInsets.symmetric(vertical: 10.0), child: Text(locale.translate(model.title), - style: aboutCardTitleStyle.copyWith( + style: fs20fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .primary)), ), ], @@ -76,7 +77,7 @@ class StudyDetailsPage extends StatelessWidget { context: context, leading: Icon(Icons.mail, color: Theme.of(context) - .extension()! + .extension()! .primary), trailing: const Icon(Icons.arrow_forward_ios, color: CACHET.GREY_6), @@ -92,7 +93,7 @@ class StudyDetailsPage extends StatelessWidget { context: context, leading: Icon(Icons.policy, color: Theme.of(context) - .extension()! + .extension()! .primary), trailing: const Icon(Icons.arrow_forward_ios, color: CACHET.GREY_6), @@ -111,7 +112,7 @@ class StudyDetailsPage extends StatelessWidget { context: context, leading: Icon(Icons.public, color: Theme.of(context) - .extension()! + .extension()! .primary), trailing: const Icon(Icons.arrow_forward_ios, color: CACHET.GREY_6), @@ -136,53 +137,53 @@ class StudyDetailsPage extends StatelessWidget { children: [ Text( locale.translate('widgets.study_card.responsible'), - style: studyDetailsInfoTitle.copyWith( + style: fs16fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900), ), Padding( padding: const EdgeInsets.only(top: 4.0, bottom: 8), child: Text( locale.translate(model.responsibleName), - style: studyDetailsInfoMessage.copyWith( + style: fs12fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey700), ), ), Text( locale.translate( 'widgets.study_card.participant_role'), - style: studyDetailsInfoTitle.copyWith( + style: fs16fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900), ), Padding( padding: const EdgeInsets.only(top: 4.0, bottom: 8), child: Text( locale.translate(model.participantRole), - style: studyDetailsInfoMessage.copyWith( + style: fs12fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey700), ), ), Text( locale.translate('widgets.study_card.device_role'), - style: studyDetailsInfoTitle.copyWith( + style: fs16fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900), ), Padding( padding: const EdgeInsets.only(top: 4.0, bottom: 8), child: Text( locale.translate(model.deviceRole), - style: studyDetailsInfoMessage.copyWith( + style: fs12fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey700), ), ), @@ -190,7 +191,7 @@ class StudyDetailsPage extends StatelessWidget { ), ), Divider( - color: Theme.of(context).extension()!.grey300, + color: Theme.of(context).extension()!.grey300, ), Padding( padding: const EdgeInsets.only(top: 16.0), @@ -201,36 +202,36 @@ class StudyDetailsPage extends StatelessWidget { Text( locale.translate( 'widgets.study_card.study_description'), - style: studyDetailsInfoTitle.copyWith( + style: fs16fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900), ), Padding( padding: const EdgeInsets.only(top: 4.0, bottom: 8), child: Text( locale.translate(model.description), - style: studyDetailsInfoMessage.copyWith( + style: fs12fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey700), ), ), Text( locale .translate('widgets.study_card.study_purpose'), - style: studyDetailsInfoTitle.copyWith( + style: fs16fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900), ), Padding( padding: const EdgeInsets.only(top: 4.0, bottom: 8), child: Text( locale.translate(model.purpose), - style: studyDetailsInfoMessage.copyWith( + style: fs12fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey700), ), ), @@ -249,7 +250,8 @@ class StudyDetailsPage extends StatelessWidget { Widget _buildSectionCard(BuildContext context, List children) { return Card( - color: Theme.of(context).extension()!.white, + margin: EdgeInsets.zero, + color: Theme.of(context).extension()!.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), @@ -259,7 +261,7 @@ class StudyDetailsPage extends StatelessWidget { children: ListTile.divideTiles( context: context, tiles: children, - color: Theme.of(context).extension()!.grey300, + color: Theme.of(context).extension()!.grey300, ).toList(), ), ), @@ -277,8 +279,8 @@ class StudyDetailsPage extends StatelessWidget { return ListTile( leading: leading, title: Text(title, - style: profileActionStyle.copyWith( - color: Theme.of(context).extension()!.grey900)), + style: fs16fw600.copyWith( + color: Theme.of(context).extension()!.grey900)), trailing: trailing, onTap: onTap, contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 16), diff --git a/lib/ui/pages/study_page.dart b/lib/ui/pages/study_page.dart index f96e3a42..6b3352b9 100644 --- a/lib/ui/pages/study_page.dart +++ b/lib/ui/pages/study_page.dart @@ -13,7 +13,8 @@ class StudyPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Theme.of(context).extension()!.backgroundGray, + backgroundColor: + Theme.of(context).extension()!.backgroundGray, body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -68,9 +69,12 @@ class StudyPageState extends State { if (LocalSettings().isAnonymous) { items.add(AnonymousCard()); } - if (bloc.messages.isNotEmpty) { + if (widget.model.messages.isNotEmpty) { items.add(_buildAnnouncementsTitle(context)); - items.addAll(bloc.messages.map((message) { + // Show newest announcements first: sort by timestamp descending + final messages = List.from(widget.model.messages) + ..sort((a, b) => b.timestamp.compareTo(a.timestamp)); + items.addAll(messages.map((message) { return _announcementCard(context, message); }).toList()); } @@ -84,7 +88,8 @@ class StudyPageState extends State { builder: (context, snapshot) { if (snapshot.data == true) { return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.grey50!, + backgroundColor: + Theme.of(context).extension()!.grey50!, elevation: 8, child: Padding( padding: const EdgeInsets.only(left: 16.0), @@ -95,9 +100,9 @@ class StudyPageState extends State { padding: const EdgeInsets.all(8.0), child: Text( locale.translate('pages.about.app_update'), - style: aboutCardSubtitleStyle.copyWith( + style: fs16fw600.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900, ), ), @@ -146,7 +151,7 @@ class StudyPageState extends State { timeago.setLocaleMessages('es', timeago.EsMessages()); return StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.grey50!, + backgroundColor: Theme.of(context).extension()!.grey50!, child: InkWell( onTap: () { if (onTap != null) { @@ -172,9 +177,10 @@ class StudyPageState extends State { Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Text(locale.translate(message.title!), - style: aboutStudyCardTitleStyle.copyWith( - color: - Theme.of(context).extension()!.primary)), + style: fs24fw700.copyWith( + color: Theme.of(context) + .extension()! + .primary)), ), if (message.subTitle != null && message.subTitle!.isNotEmpty) Row( @@ -182,9 +188,10 @@ class StudyPageState extends State { Expanded( child: Text( locale.translate(message.subTitle!), - style: aboutCardContentStyle.copyWith( - color: - Theme.of(context).extension()!.grey700, + style: fs16fw400.copyWith( + color: Theme.of(context) + .extension()! + .grey700, ), ), ), @@ -195,9 +202,9 @@ class StudyPageState extends State { Expanded( child: Text( "${locale.translate(message.message!).substring(0, (message.message!.length > 150) ? 150 : null)}...", - style: aboutCardContentStyle.copyWith( + style: fs16fw400.copyWith( color: - Theme.of(context).extension()!.grey900), + Theme.of(context).extension()!.grey900), textAlign: TextAlign.start, )), ]), @@ -215,15 +222,27 @@ class StudyPageState extends State { future: bloc.studyDeploymentStatus, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { - return Container(); + return StudiesMaterial( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 28), + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); } else if (snapshot.hasError) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 22), - child: Text('Error: ${snapshot.error}'), + return StudiesMaterial( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 28), + child: Text( + 'Error: ${snapshot.error}', + textAlign: TextAlign.center, + ), + ), ); // Show an error message if the future fails } else if (!snapshot.hasData || snapshot.data == null) { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 22), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 28), child: Center( child: CircularProgressIndicator(), ), @@ -234,7 +253,7 @@ class StudyPageState extends State { return StudiesMaterial( margin: const EdgeInsets.all(16.0), - backgroundColor: Theme.of(context).extension()!.grey50!, + backgroundColor: Theme.of(context).extension()!.grey50!, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), @@ -275,7 +294,7 @@ class StudyPageState extends State { .split('.') .last, maxLines: 2, - style: aboutCardSubtitleStyle.copyWith( + style: fs16fw600.copyWith( color: studyStatusColors[deploymentStatus]), ), ), @@ -286,9 +305,9 @@ class StudyPageState extends State { padding: const EdgeInsets.only(left: 16.0), child: Text( getStatusText(locale, deploymentStatus, snapshot), - style: aboutCardSubtitleStyle.copyWith( + style: fs16fw600.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900, fontSize: 14, ), @@ -320,8 +339,8 @@ class StudyPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(locale.translate('Announcements'), - style: aboutStudyCardTitleStyle.copyWith( - color: Theme.of(context).extension()!.grey900, + style: fs24fw700.copyWith( + color: Theme.of(context).extension()!.grey900, fontWeight: FontWeight.bold, )), ], @@ -344,7 +363,7 @@ class StudyPageState extends State { return Container( child: StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.grey50!, + backgroundColor: Theme.of(context).extension()!.grey50!, child: InkWell( onTap: () { if (onTap != null) { @@ -368,9 +387,9 @@ class StudyPageState extends State { child: Text( locale.translate(message.title!), overflow: TextOverflow.ellipsis, - style: aboutCardTitleStyle.copyWith( + style: fs20fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900, ), ), @@ -380,15 +399,8 @@ class StudyPageState extends State { color: CACHET.DEPLOYMENT_DEPLOYING, borderRadius: BorderRadius.circular(100.0), child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - locale.translate(message.type - .toString() - .split('.') - .last - .toLowerCase()), - style: aboutCardSubtitleStyle.copyWith( - color: Colors.white)), + padding: const EdgeInsets.all(4.0), + child: messageTypeIcon[message.type], ), ), ], @@ -402,9 +414,9 @@ class StudyPageState extends State { Expanded( child: Text( locale.translate(message.subTitle!), - style: aboutCardContentStyle.copyWith( + style: fs16fw400.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey700, ), ), @@ -412,9 +424,10 @@ class StudyPageState extends State { Spacer(), Text( timeago.format(message.timestamp.toLocal()), - style: aboutCardTimeAgoStyle.copyWith( - color: - Theme.of(context).extension()!.grey600, + style: fs10fw600.copyWith( + color: Theme.of(context) + .extension()! + .grey600, ), ) ], @@ -428,7 +441,7 @@ class StudyPageState extends State { locale.translate(message.message!).length > 150 ? '${locale.translate(message.message!).substring(0, 150)}...' : locale.translate(message.message!), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.start, )), ], @@ -489,6 +502,12 @@ class StudyPageState extends State { StudyDeploymentStatusTypes.Running: 'pages.about.status.running.message', StudyDeploymentStatusTypes.Stopped: 'pages.about.status.stopped.message', }; + + static Map messageTypeIcon = { + MessageType.announcement: Icon(Icons.campaign, color: Colors.white), + MessageType.news: Icon(Icons.newspaper, color: Colors.white), + MessageType.article: Icon(Icons.article, color: Colors.white), + }; } extension CopyWithAdditional on DateTime { diff --git a/lib/ui/pages/task_list_page.dart b/lib/ui/pages/task_list_page.dart index 1aec37ac..5abea3c3 100644 --- a/lib/ui/pages/task_list_page.dart +++ b/lib/ui/pages/task_list_page.dart @@ -29,7 +29,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { padding: const EdgeInsets.symmetric(vertical: 4), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), - color: Theme.of(context).extension()!.grey200, + color: Theme.of(context).extension()!.grey200, ), child: _tabBar, ); @@ -45,7 +45,7 @@ class TaskListPageState extends State with TickerProviderStateMixin { late TabController _tabController; - bool? showParticipantDataCard = false; + bool showParticipantDataCard = false; @override void initState() { @@ -69,7 +69,7 @@ class TaskListPageState extends State length: 2, child: Scaffold( backgroundColor: - Theme.of(context).extension()!.backgroundGray, + Theme.of(context).extension()!.backgroundGray, body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -97,9 +97,9 @@ class TaskListPageState extends State alignment: Alignment.centerLeft, child: Text( locale.translate('pages.task_list.title'), - style: aboutStudyCardTitleStyle.copyWith( + style: fs24fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .grey900, fontWeight: FontWeight.bold, ), @@ -125,10 +125,10 @@ class TaskListPageState extends State labelPadding: const EdgeInsets.only( top: 4, bottom: 4, left: 4, right: 4), labelColor: Theme.of(context) - .extension()! + .extension()! .grey900, unselectedLabelColor: Theme.of(context) - .extension()! + .extension()! .grey900, dividerColor: Colors.transparent, indicator: ShapeDecoration( @@ -136,7 +136,7 @@ class TaskListPageState extends State borderRadius: BorderRadius.circular(8), ), color: Theme.of(context) - .extension()! + .extension()! .white, ), tabs: [ @@ -159,7 +159,7 @@ class TaskListPageState extends State ), ), ), - if (showParticipantDataCard!) + if (showParticipantDataCard) SliverToBoxAdapter( child: _buildParticipantDataCard(), ), @@ -208,7 +208,7 @@ class TaskListPageState extends State right: Radius.circular(8.0), ), ), - backgroundColor: Theme.of(context).extension()!.grey50!, + backgroundColor: Theme.of(context).extension()!.grey50!, child: Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: IntrinsicHeight( @@ -291,7 +291,7 @@ class TaskListPageState extends State backgroundColor: userTask.expiresIn != null && userTask.expiresIn!.inHours < 24 ? CACHET.TASK_TO_EXPIRE_BACKGROUND - : Theme.of(context).extension()!.grey50!, + : Theme.of(context).extension()!.grey50!, child: Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: IntrinsicHeight( @@ -328,7 +328,7 @@ class TaskListPageState extends State color: userTask.expiresIn != null && userTask.expiresIn!.inHours < 24 ? Theme.of(context) - .extension()! + .extension()! .warningColor : Colors.grey, ), @@ -341,7 +341,7 @@ class TaskListPageState extends State color: userTask.expiresIn != null && userTask.expiresIn!.inHours < 24 ? Theme.of(context) - .extension()! + .extension()! .warningColor : Colors.grey, fontSize: 12.0, @@ -411,7 +411,7 @@ class TaskListPageState extends State userTask.onDone(); ScaffoldMessenger.of(context).showSnackBar(SnackBar( backgroundColor: - Theme.of(context).extension()!.grey700, + Theme.of(context).extension()!.grey700, content: Text(locale.translate('Done!')), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4), @@ -453,7 +453,7 @@ class TaskListPageState extends State return Icon(originalIcon.icon, color: CACHET.TASK_COMPLETED_BLUE); } else { return Icon(originalIcon.icon, - color: Theme.of(context).extension()!.grey600); + color: Theme.of(context).extension()!.grey600); } }, ); @@ -493,7 +493,7 @@ class TaskListPageState extends State return Center( child: GestureDetector( child: StudiesMaterial( - backgroundColor: Theme.of(context).extension()!.grey50!, + backgroundColor: Theme.of(context).extension()!.grey50!, hasBorder: true, shape: RoundedRectangleBorder( borderRadius: BorderRadius.horizontal( @@ -541,7 +541,7 @@ class TaskListPageState extends State color: userTask.expiresIn != null && userTask.expiresIn!.inHours < 24 ? Theme.of(context) - .extension()! + .extension()! .warningColor : Colors.grey, fontSize: 12.0, @@ -600,7 +600,7 @@ class TaskListPageState extends State padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), child: Text( locale.translate("pages.task_list.no_tasks"), - style: aboutCardSubtitleStyle, + style: fs16fw600, textAlign: TextAlign.center, )) ], diff --git a/lib/ui/tasks/audio_page.dart b/lib/ui/tasks/audio_page.dart index 74f9da9a..f236941e 100644 --- a/lib/ui/tasks/audio_page.dart +++ b/lib/ui/tasks/audio_page.dart @@ -37,7 +37,7 @@ class AudioPageState extends State { Spacer(), IconButton( color: Theme.of(context) - .extension()! + .extension()! .grey900!, onPressed: () { _showCancelConfirmationDialog(); @@ -66,16 +66,16 @@ class AudioPageState extends State { locale.translate( widget.audioUserTask!.title, ), - style: audioTitleStyle.copyWith( + style: fs22fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .primary, ), ), ), StudiesMaterial( backgroundColor: Theme.of(context) - .extension()! + .extension()! .white!, child: Scrollbar( child: SingleChildScrollView( @@ -89,7 +89,7 @@ class AudioPageState extends State { widget.audioUserTask! .instructions, ), - style: audioContentStyle, + style: fs16fw600, ), ), ), @@ -99,7 +99,7 @@ class AudioPageState extends State { CircleAvatar( radius: 30, backgroundColor: Theme.of(context) - .extension()! + .extension()! .primary, child: IconButton( onPressed: () => widget.audioUserTask! @@ -118,7 +118,7 @@ class AudioPageState extends State { child: Text( locale.translate( "pages.audio_task.play"), - style: audioContentStyle, + style: fs16fw600, ), ), ], @@ -135,16 +135,16 @@ class AudioPageState extends State { locale.translate( widget.audioUserTask!.title, ), - style: audioTitleStyle.copyWith( + style: fs22fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .primary, ), ), ), StudiesMaterial( backgroundColor: Theme.of(context) - .extension()! + .extension()! .white!, child: Scrollbar( child: SingleChildScrollView( @@ -157,7 +157,7 @@ class AudioPageState extends State { locale.translate(widget .audioUserTask! .instructions), - style: audioContentStyle, + style: fs16fw600, ), ), ), @@ -193,7 +193,7 @@ class AudioPageState extends State { child: Text( locale.translate( "pages.audio_task.recording"), - style: audioTitleStyle, + style: fs22fw700, ), ), ], @@ -209,9 +209,9 @@ class AudioPageState extends State { child: Text( locale.translate( 'pages.audio_task.done'), - style: audioTitleStyle.copyWith( + style: fs22fw700.copyWith( color: Theme.of(context) - .extension()! + .extension()! .primary, ), ), @@ -222,7 +222,7 @@ class AudioPageState extends State { child: Text( locale.translate( 'pages.audio_task.recording_completed'), - style: audioContentStyle), + style: fs16fw600), ), Spacer(), Padding( @@ -245,7 +245,7 @@ class AudioPageState extends State { icon: Icon( Icons.replay, color: Theme.of(context) - .extension()! + .extension()! .grey700, size: 30, ), diff --git a/lib/ui/tasks/audio_task_page.dart b/lib/ui/tasks/audio_task_page.dart index aa589ef8..46518caa 100644 --- a/lib/ui/tasks/audio_task_page.dart +++ b/lib/ui/tasks/audio_task_page.dart @@ -33,8 +33,9 @@ class AudioTaskPageState extends State { ), Spacer(), IconButton( - color: - Theme.of(context).extension()!.grey900!, + color: Theme.of(context) + .extension()! + .grey900!, onPressed: () { _showCancelConfirmationDialog(); }, @@ -55,7 +56,7 @@ class AudioTaskPageState extends State { Padding( padding: const EdgeInsets.symmetric(vertical: 12), child: Text(locale.translate(widget.audioUserTask!.title), - style: audioTitleStyle), + style: fs22fw700), ), Padding( padding: const EdgeInsets.symmetric( @@ -63,7 +64,7 @@ class AudioTaskPageState extends State { child: Text( '${locale.translate(widget.audioUserTask!.description)}\n\n' '${locale.translate('pages.audio_task.play')}', - style: audioContentStyle, + style: fs16fw600, ), ), Padding( @@ -89,7 +90,7 @@ class AudioTaskPageState extends State { ), style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context) - .extension()! + .extension()! .primary, padding: const EdgeInsets.symmetric( horizontal: 30, diff --git a/lib/ui/tasks/camera_page.dart b/lib/ui/tasks/camera_page.dart index 07ecc94a..eaef6e53 100644 --- a/lib/ui/tasks/camera_page.dart +++ b/lib/ui/tasks/camera_page.dart @@ -101,7 +101,7 @@ class CameraPageState extends State { } } - void stopRecording(details) async { + void stopRecording(dynamic details) async { try { var video = await _cameraController.stopVideoRecording(); diff --git a/lib/ui/tasks/camera_task_page.dart b/lib/ui/tasks/camera_task_page.dart index 251d36e9..6d827520 100644 --- a/lib/ui/tasks/camera_task_page.dart +++ b/lib/ui/tasks/camera_task_page.dart @@ -45,7 +45,7 @@ class CameraTaskPageState extends State { Spacer(), IconButton( color: Theme.of(context) - .extension()! + .extension()! .grey900!, onPressed: () { _showCancelConfirmationDialog(); @@ -74,7 +74,7 @@ class CameraTaskPageState extends State { child: Text( locale.translate( widget.mediaUserTask.title), - style: audioTitleStyle, + style: fs22fw700, ), ), Padding( @@ -83,7 +83,7 @@ class CameraTaskPageState extends State { child: Text( locale.translate( widget.mediaUserTask.description), - style: audioContentStyle, + style: fs16fw600, ), ), Padding( @@ -112,7 +112,7 @@ class CameraTaskPageState extends State { ), style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context) - .extension()! + .extension()! .primary, padding: const EdgeInsets.symmetric( horizontal: 30, diff --git a/lib/ui/tasks/display_picture_page.dart b/lib/ui/tasks/display_picture_page.dart index bd7df449..29cff952 100644 --- a/lib/ui/tasks/display_picture_page.dart +++ b/lib/ui/tasks/display_picture_page.dart @@ -60,7 +60,7 @@ class DisplayPicturePageState extends State { ), Spacer(), IconButton( - color: Theme.of(context).extension()!.grey900!, + color: Theme.of(context).extension()!.grey900!, onPressed: () { _showCancelConfirmationDialog(); }, @@ -97,14 +97,14 @@ class DisplayPicturePageState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: Text(locale.translate('pages.audio_task.done'), - style: audioTitleStyle), + style: fs22fw700), ), const SizedBox(height: 40), Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: Text( locale.translate('pages.audio_task.recording_completed'), - style: audioContentStyle, + style: fs16fw600, ), ), const SizedBox(height: 20), diff --git a/lib/ui/tasks/participant_data_page.dart b/lib/ui/tasks/participant_data_page.dart index c3397326..23c1320f 100644 --- a/lib/ui/tasks/participant_data_page.dart +++ b/lib/ui/tasks/participant_data_page.dart @@ -266,7 +266,8 @@ class ParticipantDataPageState extends State { Widget build(BuildContext context) { RPLocalizations locale = RPLocalizations.of(context)!; return Scaffold( - backgroundColor: Theme.of(context).extension()!.backgroundGray!, + backgroundColor: + Theme.of(context).extension()!.backgroundGray!, body: SafeArea( child: Container( padding: const EdgeInsets.all(16.0), @@ -283,7 +284,7 @@ class ParticipantDataPageState extends State { ), Spacer(), IconButton( - color: Theme.of(context).extension()!.grey900!, + color: Theme.of(context).extension()!.grey900!, onPressed: () { _showCancelConfirmationDialog(); }, @@ -357,7 +358,7 @@ class ParticipantDataPageState extends State { Flexible( child: Text( stepTitleMap[currentStep] ?? '', - style: healthServiceConnectMessageStyle.copyWith( + style: fs22fw700.copyWith( color: Theme.of(context).primaryColor, ), textAlign: TextAlign.center, @@ -548,7 +549,8 @@ class ParticipantDataPageState extends State { child: Container( decoration: BoxDecoration( border: Border.all( - color: Theme.of(context).extension()!.grey600!, + color: + Theme.of(context).extension()!.grey600!, width: 1.0, ), borderRadius: BorderRadius.circular(16.0), @@ -564,8 +566,9 @@ class ParticipantDataPageState extends State { showCountryOnly: true, showOnlyCountryWhenClosed: true, alignLeft: false, - textStyle: audioContentStyle.copyWith( - color: Theme.of(context).extension()!.grey900!, + textStyle: fs16fw600.copyWith( + color: + Theme.of(context).extension()!.grey900!, ), ), ), @@ -681,7 +684,7 @@ class ParticipantDataPageState extends State { _nextEnabled, ElevatedButton.styleFrom( backgroundColor: - Theme.of(context).extension()!.primary, + Theme.of(context).extension()!.primary, padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12), ), @@ -702,7 +705,7 @@ class ParticipantDataPageState extends State { currentStep == ParticipantStep.presentTypes ? true : _nextEnabled, ElevatedButton.styleFrom( backgroundColor: - Theme.of(context).extension()!.primary, + Theme.of(context).extension()!.primary, padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12), ), @@ -774,7 +777,6 @@ class ParticipantDataPageState extends State { participantData, bloc.study!.participantRoleName, ); - LocalSettings().hasSeenConnectionInstructions = true; } Future _showCancelConfirmationDialog() { diff --git a/lib/ui/widgets/charts_legend.dart b/lib/ui/widgets/charts_legend.dart index 1c17583f..12f0a434 100644 --- a/lib/ui/widgets/charts_legend.dart +++ b/lib/ui/widgets/charts_legend.dart @@ -26,7 +26,7 @@ class ChartsLegend extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title.toUpperCase(), style: dataCardTitleStyle), + Text(title.toUpperCase(), style: fs16fw400ls1), Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( @@ -39,7 +39,7 @@ class ChartsLegend extends StatelessWidget { children: [ Icon(Icons.circle, color: colors[entry.key], size: 12.0), - Text(' ${entry.value} ', style: legendStyle), + Text(' ${entry.value} ', style: fs12fw400), ], ), ) diff --git a/lib/ui/widgets/details_banner.dart b/lib/ui/widgets/details_banner.dart index d0f4c06b..cc070eb2 100644 --- a/lib/ui/widgets/details_banner.dart +++ b/lib/ui/widgets/details_banner.dart @@ -29,7 +29,7 @@ class DetailsBanner extends StatelessWidget { children: [ Text( locale.translate(title), - style: studyNameStyle.copyWith( + style: fs30fw800.copyWith( fontSize: 30, color: Theme.of(context).primaryColor), ), ], diff --git a/lib/ui/widgets/dialog_title.dart b/lib/ui/widgets/dialog_title.dart index 884f2155..51ed72ac 100644 --- a/lib/ui/widgets/dialog_title.dart +++ b/lib/ui/widgets/dialog_title.dart @@ -48,7 +48,7 @@ class DialogTitle extends StatelessWidget { (titleEnd != null ? ' ${locale.translate(titleEnd!)}' : ""), - style: sectionTitleStyle.copyWith( + style: fs18fw700.copyWith( color: Theme.of(context).primaryColor, ), textAlign: TextAlign.center, diff --git a/lib/ui/widgets/horizontal_bar.dart b/lib/ui/widgets/horizontal_bar.dart index 89e696b4..bc3b3aa6 100644 --- a/lib/ui/widgets/horizontal_bar.dart +++ b/lib/ui/widgets/horizontal_bar.dart @@ -158,7 +158,7 @@ class MyAssetsBar extends StatelessWidget { children: [ Icon(Icons.circle, color: entry.value.color, size: 12.0), Text(' ${entry.value.name!} ${entry.value.size}', - style: legendStyle, textAlign: TextAlign.right), + style: fs12fw400, textAlign: TextAlign.right), ], )), ) @@ -187,10 +187,10 @@ class MyAssetsBar extends StatelessWidget { children: [ Icon(Icons.circle, color: entry.value.color, size: 12.0), Text(' ${entry.value.size}', - style: legendStyle, textAlign: TextAlign.left), + style: fs12fw400, textAlign: TextAlign.left), Expanded( child: Text(' ${entry.value.name!}', - style: legendStyle, + style: fs12fw400, textAlign: TextAlign.left, overflow: TextOverflow.ellipsis)), ], diff --git a/lib/ui/widgets/location_permission_page.dart b/lib/ui/widgets/location_permission_page.dart index 5732b9f8..c4fce61a 100644 --- a/lib/ui/widgets/location_permission_page.dart +++ b/lib/ui/widgets/location_permission_page.dart @@ -5,7 +5,8 @@ class LocationPermissionPage { RPLocalizations locale = RPLocalizations.of(context)!; return Scaffold( - backgroundColor: Theme.of(context).extension()!.backgroundGray, + backgroundColor: + Theme.of(context).extension()!.backgroundGray, body: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: SafeArea( @@ -27,7 +28,7 @@ class LocationPermissionPage { padding: const EdgeInsets.only(top: 16.0), child: StudiesMaterial( backgroundColor: - Theme.of(context).extension()!.white!, + Theme.of(context).extension()!.white!, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), ), @@ -55,7 +56,7 @@ class LocationPermissionPage { fontWeight: FontWeight.bold, fontSize: 22.0, color: Theme.of(context) - .extension()! + .extension()! .primary, ), ), @@ -67,14 +68,14 @@ class LocationPermissionPage { child: Icon( Icons.location_on, color: Theme.of(context) - .extension()! + .extension()! .primary, size: 48, ), ), Text( locale.translate(message), - style: aboutCardContentStyle.copyWith( + style: fs16fw400.copyWith( fontWeight: FontWeight.bold, ), textAlign: TextAlign.justify, diff --git a/lib/ui/widgets/location_usage_dialog.dart b/lib/ui/widgets/location_usage_dialog.dart index 35642004..33f5599a 100644 --- a/lib/ui/widgets/location_usage_dialog.dart +++ b/lib/ui/widgets/location_usage_dialog.dart @@ -16,7 +16,7 @@ class LocationUsageDialog { height: MediaQuery.of(context).size.height * 0.15, ), Text(locale.translate("dialog.location.permission"), - style: aboutCardTitleStyle), + style: fs20fw700), ], ), contentPadding: const EdgeInsets.all(15), @@ -28,7 +28,7 @@ class LocationUsageDialog { children: [ Text( locale.translate(message), - style: aboutCardContentStyle, + style: fs16fw400, textAlign: TextAlign.justify, ), ], diff --git a/lib/view_models/tasklist_page_model.dart b/lib/view_models/tasklist_page_model.dart index 1a03b570..258d5727 100644 --- a/lib/view_models/tasklist_page_model.dart +++ b/lib/view_models/tasklist_page_model.dart @@ -34,8 +34,14 @@ class TaskListPageViewModel extends ViewModel { Stream get userTaskEvents => AppTaskController().userTaskEvents; /// The number of days the user has been part of this study. - int get daysInStudy => (bloc.studyStartTimestamp != null) - ? DateTime.now().difference(bloc.studyStartTimestamp!).inDays + 1 + /// + /// This is calculated from the study deployment status creation date from the + /// [StudyDeploymentStatus]. + /// Returns 0 if the study deployment status is not available. + int get daysInStudy => (Sensing().studyDeploymentStatus != null) + ? DateTime.now() + .difference(Sensing().studyDeploymentStatus!.createdOn) + .inDays : 0; /// The number of tasks completed so far. diff --git a/lib/view_models/view_model.dart b/lib/view_models/view_model.dart index 447535f5..9585bb84 100644 --- a/lib/view_models/view_model.dart +++ b/lib/view_models/view_model.dart @@ -15,11 +15,12 @@ abstract class ViewModel extends ChangeNotifier { _controller = ctrl; } - /// Called when this view model is to clear its state (e.g., cached data). + /// Clear this view model, i.e. delete all data incl. cached data. @mustCallSuper void clear() {} - /// Called when this view model is disposed and no longer used. + /// Called when this view model is disposed. Typically on app exit, incl. when + /// closed by the OS. @override @mustCallSuper void dispose() { @@ -92,7 +93,7 @@ abstract class SerializableViewModel extends ViewModel { _filename = null; _persistenceTimer?.cancel(); _persistenceTimer = null; - save(); + delete(); } @override @@ -127,7 +128,7 @@ abstract class SerializableViewModel extends ViewModel { return success; } - /// Permanently delete the [model]. + /// Permanently delete the cached [model]. /// Returns true if successful, false otherwise. bool delete() { bool success = true; diff --git a/pubspec.lock b/pubspec.lock index f41a83b7..cd7fe24a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -89,6 +89,62 @@ packages: url: "https://pub.dev" source: hosted version: "4.2.2" + audioplayers: + dependency: transitive + description: + name: audioplayers + sha256: "5441fa0ceb8807a5ad701199806510e56afde2b4913d9d17c2f19f2902cf0ae4" + url: "https://pub.dev" + source: hosted + version: "6.5.1" + audioplayers_android: + dependency: transitive + description: + name: audioplayers_android + sha256: "60a6728277228413a85755bd3ffd6fab98f6555608923813ce383b190a360605" + url: "https://pub.dev" + source: hosted + version: "5.2.1" + audioplayers_darwin: + dependency: transitive + description: + name: audioplayers_darwin + sha256: "0811d6924904ca13f9ef90d19081e4a87f7297ddc19fc3d31f60af1aaafee333" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + audioplayers_linux: + dependency: transitive + description: + name: audioplayers_linux + sha256: f75bce1ce864170ef5e6a2c6a61cd3339e1a17ce11e99a25bae4474ea491d001 + url: "https://pub.dev" + source: hosted + version: "4.2.1" + audioplayers_platform_interface: + dependency: transitive + description: + name: audioplayers_platform_interface + sha256: "0e2f6a919ab56d0fec272e801abc07b26ae7f31980f912f24af4748763e5a656" + url: "https://pub.dev" + source: hosted + version: "7.1.1" + audioplayers_web: + dependency: transitive + description: + name: audioplayers_web + sha256: "1c0f17cec68455556775f1e50ca85c40c05c714a99c5eb1d2d57cc17ba5522d7" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + audioplayers_windows: + dependency: transitive + description: + name: audioplayers_windows + sha256: "4048797865105b26d47628e6abb49231ea5de84884160229251f37dfcbe52fd7" + url: "https://pub.dev" + source: hosted + version: "4.2.1" base_codecs: dependency: transitive description: @@ -321,6 +377,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + carp_themes_package: + dependency: "direct main" + description: + name: carp_themes_package + sha256: "48e747c82392db406531289828b4143275b28736354fb9e7bc62cfe1a189d675" + url: "https://pub.dev" + source: hosted + version: "0.0.3" carp_webservices: dependency: "direct main" description: @@ -1633,10 +1697,10 @@ packages: dependency: "direct main" description: name: research_package - sha256: "956cc0a8eba67174d17ac686998ef65c0b553cffec4b33fee507ddb51b9c29fd" + sha256: da2f8819f53f52dbc3ecce1c64fbc3208e7f75e35877c91366f598ff7857472d url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" retry: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 428642a4..be151299 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: carp_study_app description: The generic CARP study app. publish_to: "none" -version: 4.1.1+88 +version: 4.2.0+90 environment: sdk: ">=3.2.0 <4.0.0" @@ -21,11 +21,12 @@ dependencies: carp_polar_package: ^1.6.1 carp_health_package: ^3.2.0 carp_movesense_package: ^1.7.2 + carp_themes_package: ^0.0.1 carp_webservices: ^3.8.0 carp_backend: ^1.9.2 - research_package: ^2.0.0 + research_package: ^2.2.0 cognition_package: ^1.6.1 url_launcher: ^6.1.5 @@ -69,7 +70,7 @@ dependency_overrides: # carp_core: # path: ../carp/carp.sensing-flutter/carp_core/ # carp_mobile_sensing: - # path: ../carp/carp.sensing-flutter/carp_mobile_sensing/ + # path: ../carp.sensing-flutter/carp_mobile_sensing/ # carp_context_package: # path: ../carp/carp.sensing-flutter/packages/carp_context_package/ # carp_connectivity_package: