diff --git a/.github/workflows/app.yml b/.github/workflows/app.yml
index 9edffd0c3..25128bfb9 100644
--- a/.github/workflows/app.yml
+++ b/.github/workflows/app.yml
@@ -11,9 +11,9 @@ defaults:
working-directory: ./app
env:
- JAVA_VERSION: 12.x
+ JAVA_VERSION: 17.x
FLUTTER_CHANNEL: stable
- FLUTTER_VERSION: 3.7.6
+ FLUTTER_VERSION: 3.16.4
jobs:
lint:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 31dea12d6..b5da93f09 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -9,18 +9,23 @@ Before you begin with setting up your local development environment, ensure that
you have the following list of tools installed:
- An editor, we **strongly recommend** [ Visual Studio Code](https://code.visualstudio.com)
- [ Git](https://git-scm.com/downloads)
- [ Docker](https://docs.docker.com/get-docker/)
- [ NodeJS](https://nodejs.org)
- [ Yarn](https://yarnpkg.com/)
diff --git a/app/.gitignore b/app/.gitignore
index a80a374fb..4ff0d8334 100644
--- a/app/.gitignore
+++ b/app/.gitignore
@@ -30,6 +30,7 @@
.pub-cache/
.pub/
/build/
+devtools_options.yaml
# Web related
lib/generated_plugin_registrant.dart
diff --git a/app/CONTRIBUTING.md b/app/CONTRIBUTING.md
index 395707cfa..1c47088e6 100644
--- a/app/CONTRIBUTING.md
+++ b/app/CONTRIBUTING.md
@@ -11,8 +11,8 @@ Please also see the [contribution guide in the root folder](../CONTRIBUTING.md).
- Run `dart pub get` to fetch all dart dependencies
- Run `flutter pub get` to fetch all flutter dependencies and setup all
generated code
- - Run `flutter pub run build_runner build --delete-conflicting-outputs` or
- `flutter pub run build_runner watch --delete-conflicting-outputs` to
+ - Run `dart run build_runner build --delete-conflicting-outputs` or
+ `dart run build_runner watch --delete-conflicting-outputs` to
re-generate code upon file changes while developing
You should now be able to run the app by opening the debug panel on the left and
@@ -24,42 +24,71 @@ For (cleaning) generated code, you might want to add the following aliases to
your shell configuration:
```bash
-alias flutter-generate='flutter pub run build_runner build --delete-conflicting-outputs'
+alias flutter-generate='dart run build_runner build --delete-conflicting-outputs'
alias flutter-clean='find . -maxdepth 20 -type f \( -name "*.inject.summary" -o -name "*.inject.dart" -o -name "*.g.dart" \) -delete'
```
## Architecture
-The app consists of multiple so-called modules. Our main modules correspond to
-the direct subfolders of `lib/`.
+The app consists of multiple so-called modules. Our main modules (usually app
+screens) correspond to the direct subfolders of `lib/`.
-### Example Module
+Common functions used by modules such as `models`, `widgets`, and `utilities`
+are living in `common`. All such functions are exported from
+`common/module.dart`.
-Structure of `lib/my_module`:
+The structure of an example module `lib/my_module` should look as follows:
- `my_module`
- - `module.dart`:
- - exports everything that is required by other modules
- - declares all routes as a const variable (`myModuleRoutes`)
+ - `module.dart` (see example below):
+ - exports everything that is required by other modules, i.e., page(s) and
+ possibly the cubit
+ - declares all routes as functions reeturning `AutoRoute`
- may contain initialization code (`initMyModule()`)
- - `cubit.dart`: contains `MyModuleCubit` and `MyModuleState`s
- `widgets`:
- `my_widget.dart`: contains `MyWidget` and helpers
- `pages`:
- - `my_first.dart`: contains `MyFirstPage` and helpers
- - `my_complex`: create a folder for complex pages (e.g., tabbed ones)
- - `page.dart`: contains `MyComplexPage`
- - `tab_first.dart`: contains `FirstTab` and helpers
- - `tab_second.dart`: contains `SecondTab` and helpers
- - `utils.dart`: contains utilities used by multiple files in this page
+ - `my_module.dart`: contains `MyModulePage` and helpers
+ - `my_child_page.dart`: contains
+ - `my_complex_page`: create a folder for complex pages (e.g., tabbed ones);
+ might want to create an own module if getting too complex
- `utils.dart`: contains utilities used throughout this module
- - `submodule_one`
- - `submodule_two`
-
-If a single file gets too complex for routes, the `Cubit`, a widget, a page,
-etc., you can create a folder with the same name and split the original file
-into different files. An example of that is `MyComplexPage` in the file tree
-above.
+ - `cubit.dart`: contains `MyModuleCubit` and `MyModuleState`s (if needed)
+
+Example for `my_module/module.dart`; the page is used as a root page in the tab
+router, which is why the empty router `MyModuleRootPage` and adding
+`AutoRoute(path: '', page: MyModuleRoute.page)` to children is needed.
+
+```dart
+import '../common/module.dart';
+
+// For generated routes
+export 'cubit.dart';
+export 'pages/my_module.dart';
+export 'pages/my_child_page.dart';
+export 'pages/my_complex_page/page.dart';
+
+@RoutePage()
+class MyModuleRootPage extends AutoRouter {}
+
+AutoRoute myChildRoute() => AutoRoute(
+ path: 'my_child',
+ page: MyChildRoute.page,
+);
+AutoRoute myComplexRoute() => AutoRoute(
+ path: 'my_complex',
+ page: MyComplexRoute.page,
+);
+
+AutoRoute myModuleRoute({ required List children }) => AutoRoute(
+ path: 'my_module',
+ page: MyModuleRootRoute.page,
+ children: [
+ AutoRoute(path: '', page: MyModuleRoute.page),
+ ...children, // includes myChildRoute() and priva
+ ],
+);
+```
## Making app icons
diff --git a/app/android/app/build.gradle b/app/android/app/build.gradle
index e9a640652..f35701529 100644
--- a/app/android/app/build.gradle
+++ b/app/android/app/build.gradle
@@ -26,15 +26,17 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
- compileSdkVersion 33
+ namespace 'de.hpi.pharme'
+
+ compileSdk 33
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
- jvmTarget = '1.8'
+ jvmTarget = '17'
}
sourceSets {
@@ -42,8 +44,7 @@ android {
}
defaultConfig {
- // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
- applicationId "de.hpi.pharme"
+ applicationId 'de.hpi.pharme'
minSdkVersion 19
targetSdkVersion 33
multiDexEnabled true
diff --git a/app/android/app/src/debug/AndroidManifest.xml b/app/android/app/src/debug/AndroidManifest.xml
index d1df7c5b4..f880684a6 100644
--- a/app/android/app/src/debug/AndroidManifest.xml
+++ b/app/android/app/src/debug/AndroidManifest.xml
@@ -1,5 +1,4 @@
-
+
diff --git a/app/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml
index d07f3150a..beab9a926 100644
--- a/app/android/app/src/main/AndroidManifest.xml
+++ b/app/android/app/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
-
+
diff --git a/app/android/app/src/profile/AndroidManifest.xml b/app/android/app/src/profile/AndroidManifest.xml
index d1df7c5b4..f880684a6 100644
--- a/app/android/app/src/profile/AndroidManifest.xml
+++ b/app/android/app/src/profile/AndroidManifest.xml
@@ -1,5 +1,4 @@
-
+
diff --git a/app/android/build.gradle b/app/android/build.gradle
index 76374445e..aca8b4a20 100644
--- a/app/android/build.gradle
+++ b/app/android/build.gradle
@@ -1,12 +1,12 @@
buildscript {
- ext.kotlin_version = '1.6.21'
+ ext.kotlin_version = '1.8.0'
repositories {
google()
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.1.0'
+ classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@@ -24,6 +24,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
-task clean(type: Delete) {
+tasks.register("clean", Delete) {
delete rootProject.buildDir
}
diff --git a/app/android/gradle.properties b/app/android/gradle.properties
index 94adc3a3f..b9a9a2464 100644
--- a/app/android/gradle.properties
+++ b/app/android/gradle.properties
@@ -1,3 +1,6 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
+android.defaults.buildfeatures.buildconfig=true
+android.nonTransitiveRClass=false
+android.nonFinalResIds=false
diff --git a/app/android/gradle/wrapper/gradle-wrapper.properties b/app/android/gradle/wrapper/gradle-wrapper.properties
index bc6a58afd..5c6f89dba 100644
--- a/app/android/gradle/wrapper/gradle-wrapper.properties
+++ b/app/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
-#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
diff --git a/app/generate_screenshots/app_test.dart b/app/generate_screenshots/app_test.dart
index c33e5014b..cf1cddd59 100644
--- a/app/generate_screenshots/app_test.dart
+++ b/app/generate_screenshots/app_test.dart
@@ -3,6 +3,7 @@
import 'dart:io';
+import 'package:app/app.dart';
import 'package:app/common/module.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -51,6 +52,8 @@ void main() {
await takeScreenshot(tester, binding, 'login');
// login-redirect (not working; only taking screenshot of loading screen)
+ // could try to use cubit function to directly sign in which will only
+ // open the webview and close it again
// await tester.tap(find.byType(FullWidthButton).first);
// await Future.delayed(Duration(seconds: 3)); // wait for dialog
// await takeScreenshot(tester, binding, 'login-redirect');
diff --git a/app/generate_screenshots/test_driver.dart b/app/generate_screenshots/test_driver.dart
index 5dee08a09..d7bd66f77 100644
--- a/app/generate_screenshots/test_driver.dart
+++ b/app/generate_screenshots/test_driver.dart
@@ -7,7 +7,7 @@ import 'package:integration_test/integration_test_driver_extended.dart';
Future main() async {
try {
await integrationDriver(
- onScreenshot: (screenshotName, screenshotBytes) async {
+ onScreenshot: (screenshotName, screenshotBytes, [_]) async {
final image =
await File(
'../docs/screenshots/$screenshotName.png'
diff --git a/app/integration_test/drugs_test.dart b/app/integration_test/drugs_test.dart
index bc87a03bd..b3bbca4e9 100644
--- a/app/integration_test/drugs_test.dart
+++ b/app/integration_test/drugs_test.dart
@@ -1,8 +1,8 @@
// ignore_for_file: cast_nullable_to_non_nullable
import 'package:app/common/module.dart';
-import 'package:app/common/pages/drug/widgets/module.dart';
-import 'package:app/search/module.dart';
+import 'package:app/drug/module.dart';
+import 'package:app/drug/widgets/annotation_cards/disclaimer.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -126,7 +126,7 @@ void main() {
// test the right color of the card
// ignore: omit_local_variable_types
- final Card card = tester.firstWidget(
+ final RoundedCard card = tester.firstWidget(
find.byKey(
ValueKey('annotationCard'),
),
@@ -136,14 +136,14 @@ void main() {
testDrug.guidelines.first.annotations.warningLevel.color,
);
- context = tester.element(find.byType(Tooltip).first);
-
// test that drug activity can be set
- final checkbox = tester.widget(find.byType(CheckboxListTile))
- as CheckboxListTile;
- expect(checkbox.onChanged, isNotNull);
+ final activitySelection = tester.firstWidget(
+ find.byType(DropdownButton)
+ ) as DropdownButton;
+ expect(activitySelection.onChanged, isNotNull);
// test tooltips
+ context = tester.element(find.byType(Tooltip).first);
expect(
find.byTooltip(context.l10n.drugs_page_tooltip_guideline),
findsOneWidget,
@@ -202,9 +202,10 @@ void main() {
),
);
- final checkbox = tester.widget(find.byType(CheckboxListTile))
- as CheckboxListTile;
- expect(checkbox.onChanged, isNull);
+ final activitySelection = tester.firstWidget(
+ find.byType(DropdownButton)
+ ) as DropdownButton;
+ expect(activitySelection.onChanged, isNull);
});
});
}
diff --git a/app/integration_test/faq_test.dart b/app/integration_test/faq_test.dart
index 57f91406c..f54190a66 100644
--- a/app/integration_test/faq_test.dart
+++ b/app/integration_test/faq_test.dart
@@ -14,7 +14,7 @@ void main() {
final faqWidget = MaterialApp.router(
routeInformationParser: appRouter.defaultRouteParser(),
routerDelegate: appRouter.delegate(
- initialDeepLink: 'main/faq',
+ deepLinkBuilder: (_) => DeepLink.path('/main/faq'),
),
localizationsDelegates: [
AppLocalizations.delegate,
diff --git a/app/integration_test/login_test.dart b/app/integration_test/login_test.dart
index ed077c69b..76f9dbbfc 100644
--- a/app/integration_test/login_test.dart
+++ b/app/integration_test/login_test.dart
@@ -8,8 +8,8 @@ import 'package:integration_test/integration_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:provider/provider.dart';
-class MockLoginCubit extends MockCubit
- implements LoginPageCubit {}
+class MockLoginCubit extends MockCubit
+ implements LoginCubit {}
void main() {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -20,7 +20,7 @@ void main() {
group('integration tests for the login page', () {
testWidgets('test loading state', (tester) async {
when(() => mockLoginCubit.state).thenReturn(
- LoginPageState.loadingUserData(),
+ LoginState.loadingUserData(),
);
await tester.pumpWidget(
@@ -44,7 +44,7 @@ void main() {
testWidgets('test error state', (tester) async {
when(() => mockLoginCubit.state).thenReturn(
- LoginPageState.error('Some error'),
+ LoginState.error('Some error'),
);
await tester.pumpWidget(
@@ -70,7 +70,7 @@ void main() {
testWidgets('test loaded state', (tester) async {
when(() => mockLoginCubit.state).thenReturn(
- LoginPageState.loadedUserData(),
+ LoginState.loadedUserData(),
);
await tester.pumpWidget(
@@ -97,7 +97,7 @@ void main() {
testWidgets('test initial state', (tester) async {
when(() => mockLoginCubit.state).thenReturn(
- LoginPageState.initial(),
+ LoginState.initial(),
);
await tester.pumpWidget(
diff --git a/app/integration_test/main_page_test.dart b/app/integration_test/main_page_test.dart
index 992acb46f..be977bd12 100644
--- a/app/integration_test/main_page_test.dart
+++ b/app/integration_test/main_page_test.dart
@@ -1,4 +1,3 @@
-import 'package:app/common/models/drug/cached_drugs.dart';
import 'package:app/common/module.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -25,7 +24,7 @@ void main() {
child: MaterialApp.router(
routeInformationParser: appRouter.defaultRouteParser(),
routerDelegate: appRouter.delegate(
- initialDeepLink: 'main',
+ deepLinkBuilder: (_) => DeepLink.path('/main'),
),
localizationsDelegates: [
AppLocalizations.delegate,
diff --git a/app/integration_test/settings_test.dart b/app/integration_test/more_test.dart
similarity index 95%
rename from app/integration_test/settings_test.dart
rename to app/integration_test/more_test.dart
index 8954b95e7..02b7b2633 100644
--- a/app/integration_test/settings_test.dart
+++ b/app/integration_test/more_test.dart
@@ -15,7 +15,7 @@ void main() {
debugShowCheckedModeBanner: false,
routeInformationParser: appRouter.defaultRouteParser(),
routerDelegate: appRouter.delegate(
- initialDeepLink: 'main/settings',
+ deepLinkBuilder: (_) => DeepLink.path('/main/more'),
),
localizationsDelegates: [
AppLocalizations.delegate,
@@ -65,7 +65,7 @@ void main() {
findsOneWidget,
);
- context.router.navigateBack();
+ context.router.back();
await tester.pumpAndSettle();
// test privacy policy
@@ -77,7 +77,7 @@ void main() {
findsOneWidget,
);
- context.router.navigateBack();
+ context.router.back();
await tester.pumpAndSettle();
// test terms and conditions
diff --git a/app/integration_test/onboarding_test.dart b/app/integration_test/onboarding_test.dart
index 6fe261d95..10f1f4345 100644
--- a/app/integration_test/onboarding_test.dart
+++ b/app/integration_test/onboarding_test.dart
@@ -1,5 +1,5 @@
import 'package:app/common/module.dart';
-import 'package:app/onboarding/pages/onboarding.dart';
+import 'package:app/onboarding/module.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock
index 20a82c12e..df08f0612 100644
--- a/app/ios/Podfile.lock
+++ b/app/ios/Podfile.lock
@@ -2,24 +2,26 @@ PODS:
- device_info_plus (0.0.1):
- Flutter
- Flutter (1.0.0)
- - flutter_secure_storage (3.3.1):
+ - flutter_secure_storage (6.0.0):
- Flutter
- flutter_share (0.0.1):
- Flutter
- - flutter_web_auth (0.4.1):
+ - flutter_web_auth (0.5.0):
- Flutter
- integration_test (0.0.1):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- - path_provider_ios (0.0.1):
+ - path_provider_foundation (0.0.1):
- Flutter
+ - FlutterMacOS
- printing (1.0.0):
- Flutter
- sensors_plus (0.0.1):
- Flutter
- - shared_preferences_ios (0.0.1):
+ - shared_preferences_foundation (0.0.1):
- Flutter
+ - FlutterMacOS
- url_launcher_ios (0.0.1):
- Flutter
@@ -31,10 +33,10 @@ DEPENDENCIES:
- flutter_web_auth (from `.symlinks/plugins/flutter_web_auth/ios`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
+ - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- printing (from `.symlinks/plugins/printing/ios`)
- sensors_plus (from `.symlinks/plugins/sensors_plus/ios`)
- - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
+ - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
EXTERNAL SOURCES:
@@ -52,30 +54,30 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/integration_test/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
- path_provider_ios:
- :path: ".symlinks/plugins/path_provider_ios/ios"
+ path_provider_foundation:
+ :path: ".symlinks/plugins/path_provider_foundation/darwin"
printing:
:path: ".symlinks/plugins/printing/ios"
sensors_plus:
:path: ".symlinks/plugins/sensors_plus/ios"
- shared_preferences_ios:
- :path: ".symlinks/plugins/shared_preferences_ios/ios"
+ shared_preferences_foundation:
+ :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
- device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
+ device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
- flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
+ flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
flutter_share: 4be0208963c60b537e6255ed2ce1faae61cd9ac2
- flutter_web_auth: 09a0abd245f1a07a3ff4dcf1247a048d89ee12a9
- integration_test: a1e7d09bd98eca2fc37aefd79d4f41ad37bdbbe5
- package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
- path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
- printing: eafa00acb682c0ca029d4d98d0798f55a1e27102
+ flutter_web_auth: c25208760459cec375a3c39f6a8759165ca0fa4d
+ integration_test: 13825b8a9334a850581300559b8839134b124670
+ package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
+ path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
+ printing: 233e1b73bd1f4a05615548e9b5a324c98588640b
sensors_plus: 5717760720f7e6acd96fdbd75b7428f5ad755ec2
- shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
- url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
+ shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
+ url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
diff --git a/app/ios/Runner.xcodeproj/project.pbxproj b/app/ios/Runner.xcodeproj/project.pbxproj
index 51341095d..c599db8d7 100644
--- a/app/ios/Runner.xcodeproj/project.pbxproj
+++ b/app/ios/Runner.xcodeproj/project.pbxproj
@@ -155,7 +155,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1300;
+ LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -226,6 +226,7 @@
files = (
);
inputPaths = (
+ "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
diff --git a/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 3db53b6e1..b52b2e698 100644
--- a/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
LSSupportsOpeningDocumentsInPlace
UIFileSharingEnabled
-
+
UIApplicationSupportsIndirectInputEvents
+ FLTEnableImpeller
+
diff --git a/app/lib/common/widgets/app.dart b/app/lib/app.dart
similarity index 57%
rename from app/lib/common/widgets/app.dart
rename to app/lib/app.dart
index 9ba3bfd21..35709ac32 100644
--- a/app/lib/common/widgets/app.dart
+++ b/app/lib/app.dart
@@ -1,37 +1,24 @@
import 'package:flutter_localizations/flutter_localizations.dart';
-import '../models/metadata.dart';
-import '../module.dart' hide MetaData;
+import 'common/module.dart';
class PharMeApp extends StatelessWidget {
factory PharMeApp() => _instance;
- PharMeApp._({Key? key}) : super(key: key);
+ PharMeApp._();
static final _instance = PharMeApp._();
static GlobalKey get navigatorKey =>
_instance._appRouter.navigatorKey;
final _appRouter = AppRouter();
- final _isLoggedIn = MetaData.instance.isLoggedIn ?? false;
- final _onboardingDone = MetaData.instance.onboardingDone ?? false;
- final _initialDrugSelectionDone =
- MetaData.instance.initialDrugSelectionDone ?? false;
@override
Widget build(BuildContext context) {
return MaterialApp.router(
debugShowCheckedModeBanner: false,
routeInformationParser: _appRouter.defaultRouteParser(),
- routerDelegate: _appRouter.delegate(
- initialDeepLink: !_isLoggedIn
- ? 'login'
- : !_onboardingDone
- ? 'onboarding'
- : !_initialDrugSelectionDone
- ? 'drugselection'
- : 'main',
- ),
+ routerDelegate: _appRouter.delegate(deepLinkBuilder: getInitialRoute),
theme: PharMeTheme.light,
localizationsDelegates: [
AppLocalizations.delegate,
diff --git a/app/lib/common/models/module.dart b/app/lib/common/models/module.dart
index 30f7b4735..a1c47b710 100644
--- a/app/lib/common/models/module.dart
+++ b/app/lib/common/models/module.dart
@@ -1,4 +1,5 @@
export 'anni_response.dart';
+export 'drug/cached_drugs.dart';
export 'drug/drug.dart';
export 'drug/drug_inhibitors.dart';
export 'drug/guideline.dart';
diff --git a/app/lib/common/pages/drug/widgets/adaptive_dialog.dart b/app/lib/common/pages/drug/widgets/adaptive_dialog.dart
deleted file mode 100644
index 48a7374a3..000000000
--- a/app/lib/common/pages/drug/widgets/adaptive_dialog.dart
+++ /dev/null
@@ -1,87 +0,0 @@
-import 'package:flutter/cupertino.dart';
-
-import '../../../module.dart';
-
-class AdaptiveAlertDialog extends StatelessWidget {
- const AdaptiveAlertDialog({
- Key? key,
- required this.title,
- required this.content,
- required this.actions,
- }) : super(key: key);
-
- final String title;
- final Widget? content;
- final List actions;
-
- @override
- Widget build(BuildContext context) {
- switch (getPlatform()) {
- case SupportedPlatform.android:
- return AlertDialog(
- title: Text(title),
- content: content,
- actions: actions,
- );
- case SupportedPlatform.ios:
- return CupertinoAlertDialog(
- title: Text(title),
- content: Card(
- color: Colors.transparent,
- elevation: 0,
- child: content,
- ),
- actions: actions,
- );
- }
- }
-}
-
-class AdaptiveDialogAction extends StatelessWidget {
- const AdaptiveDialogAction({
- Key? key,
- this.isDefault = false,
- this.isDestructive = false,
- this.onPressed,
- required this.text,
- }) : super(key: key);
-
- final bool isDefault;
- final bool isDestructive;
- final void Function()? onPressed;
- final String text;
-
- @override
- Widget build(BuildContext context) {
- switch (getPlatform()) {
- case SupportedPlatform.android:
- return TextButton(
- onPressed: onPressed,
- child: Text(text, style: onPressed != null
- ? isDestructive
- ? TextStyle(color: PharMeTheme.errorColor)
- : TextStyle(color: PharMeTheme.primaryColor)
- : TextStyle(color: PharMeTheme.onSurfaceColor)),
- );
- case SupportedPlatform.ios:
- return CupertinoDialogAction(
- isDefaultAction: isDefault,
- isDestructiveAction: isDestructive,
- onPressed: onPressed,
- child: Text(text),
- );
- }
- }
-}
-
-Future showAdaptiveDialog({
- required BuildContext context,
- required Widget Function(BuildContext) builder,
-}) {
- switch (getPlatform()) {
- case SupportedPlatform.android:
- return showDialog(context: context, builder: builder);
- case SupportedPlatform.ios:
- return showCupertinoDialog(context: context, builder: builder);
- }
-}
\ No newline at end of file
diff --git a/app/lib/common/pages/drug/widgets/annotation_cards/drug.dart b/app/lib/common/pages/drug/widgets/annotation_cards/drug.dart
deleted file mode 100644
index 06289ca16..000000000
--- a/app/lib/common/pages/drug/widgets/annotation_cards/drug.dart
+++ /dev/null
@@ -1,96 +0,0 @@
-import '../../../../module.dart';
-import '../adaptive_dialog.dart';
-import '../sub_header.dart';
-
-class DrugAnnotationCard extends StatelessWidget {
- const DrugAnnotationCard(
- this.drug, {
- required this.isActive,
- required this.setActivity,
- this.disabled = false,
- });
-
- final Drug drug;
- final bool isActive;
- final void Function(bool?) setActivity;
- final bool disabled;
-
- @override
- Widget build(BuildContext context) {
- return RoundedCard(
- child: SingleChildScrollView(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- SubHeader(context.l10n.drugs_page_header_druginfo),
- SizedBox(height: 12),
- Text(drug.annotations.indication),
- SizedBox(height: 8),
- Table(defaultColumnWidth: IntrinsicColumnWidth(), children: [
- _buildRow(context.l10n.drugs_page_header_drugclass,
- drug.annotations.drugclass),
- if (drug.annotations.brandNames.isNotEmpty) ...[
- _buildRow(context.l10n.drugs_page_header_synonyms,
- drug.annotations.brandNames.join(', ')),
- ]
- ]),
- SizedBox(height: 4),
- if (isInhibitor(drug.name)) ...[
- SizedBox(height: 8),
- Text(context.l10n.drugs_page_is_inhibitor(
- drug.name,
- inhibitedGenes(drug).join(', '),
- )),
- ],
- Divider(color: PharMeTheme.borderColor),
- SizedBox(height: 4),
- SubHeader(context.l10n.drugs_page_header_active),
- CheckboxListTile(
- activeColor: PharMeTheme.primaryColor,
- title: Text(context.l10n.drugs_page_active),
- value: isActive,
- onChanged: disabled ? null : (newValue) => {
- if (isInhibitor(drug.name)) {
- showAdaptiveDialog(
- context: context,
- builder: (context) => AdaptiveAlertDialog(
- title: context.l10n.drugs_page_active_warn_header,
- content: Text(context.l10n.drugs_page_active_warn),
- actions: [
- AdaptiveDialogAction(
- isDefault: true,
- onPressed: () => Navigator.pop(context, 'Cancel'),
- text: context.l10n.action_cancel,
- ),
- AdaptiveDialogAction(
- isDestructive: true,
- onPressed: () {
- Navigator.pop(context, 'OK');
- setActivity(newValue);
- },
- text: context.l10n.action_continue,
- ),
- ],
- ),
- )
- } else {
- setActivity(newValue)
- }
- },
- controlAffinity: ListTileControlAffinity.leading,
- ),
- ],
- ),
- ),
- );
- }
-
- TableRow _buildRow(String key, String value) => TableRow(children: [
- Padding(
- padding: EdgeInsets.fromLTRB(0, 4, 12, 4),
- child: Text(key,
- style: PharMeTheme.textTheme.bodyMedium!
- .copyWith(fontWeight: FontWeight.bold))),
- Padding(padding: EdgeInsets.fromLTRB(0, 4, 0, 4), child: Text(value)),
- ]);
-}
diff --git a/app/lib/common/pages/drug/widgets/annotation_cards/guideline.dart b/app/lib/common/pages/drug/widgets/annotation_cards/guideline.dart
deleted file mode 100644
index 9eb3b6c31..000000000
--- a/app/lib/common/pages/drug/widgets/annotation_cards/guideline.dart
+++ /dev/null
@@ -1,145 +0,0 @@
-import 'package:url_launcher/url_launcher.dart';
-
-import '../../../../module.dart';
-import '../sub_header.dart';
-
-class GuidelineAnnotationCard extends StatelessWidget {
- const GuidelineAnnotationCard(this.drug);
-
- final Drug drug;
-
- @override
- Widget build(BuildContext context) {
- return RoundedCard(
- padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
- child: SingleChildScrollView(
- child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
- _buildHeader(context),
- SizedBox(height: 12),
- if (drug.userGuideline != null) ...[
- _buildCard(context),
- SizedBox(height: 8),
- Divider(color: PharMeTheme.borderColor),
- SizedBox(height: 8),
- _buildSourcesSection(context),
- SizedBox(height: 12),
- ]
- else ...[
- _buildCard(context),
- SizedBox(height: 16),
- ],
- ]),
- ),
- );
- }
-
- Widget _buildCard(BuildContext context) {
- final upperCardText = drug.userGuideline?.annotations.implication ??
- context.l10n.drugs_page_no_guidelines_for_phenotype_implication(
- drug.name
- );
- final lowerCardText = drug.userGuideline?.annotations.recommendation ??
- context.l10n.drugs_page_no_guidelines_for_phenotype_recommendation;
- return Card(
- key: Key('annotationCard'),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(12),
- ),
- color: drug.warningLevel.color,
- child: Padding(
- padding: EdgeInsets.all(12),
- child:
- Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
- Row(children: [
- Icon(
- drug.warningLevel.icon,
- color: PharMeTheme.onSurfaceText,
- ),
- SizedBox(width: 12),
- Flexible(
- child: Text(
- upperCardText,
- style: PharMeTheme.textTheme.bodyMedium,
- ),
- )
- ]),
- SizedBox(height: 12),
- Text(
- lowerCardText,
- style: PharMeTheme.textTheme.bodyMedium,
- ),
- ])));
- }
-
- Widget _buildHeader(BuildContext context) {
- var headerContent = '';
- var headerStyle = PharMeTheme.textTheme.bodyLarge!;
- if (drug.userGuideline == null && drug.guidelines.isEmpty) {
- headerContent = context.l10n.drugs_page_guidelines_empty(drug.name);
- headerStyle = headerStyle.copyWith(fontStyle: FontStyle.italic);
- } else {
- final genes = drug.userGuideline?.lookupkey.keys ??
- drug.guidelines.first.lookupkey.keys;
- final geneDescriptions = genes.map((geneSymbol) {
- final phenotypeInformation = UserData.phenotypeFor(
- geneSymbol,
- context,
- drug: drug.name,
- );
- var description = '$geneSymbol: ${phenotypeInformation.phenotype}';
- if (phenotypeInformation.adaptionText.isNotNullOrBlank) {
- description = '$description (${phenotypeInformation.adaptionText})';
- }
- return description;
- });
- headerContent = geneDescriptions.join('\n');
- }
- return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
- SubHeader(context.l10n.drugs_page_your_genome),
- SizedBox(height: 12),
- Text(
- headerContent,
- style: headerStyle,
- ),
- ]);
- }
-
- Widget _buildSourcesSection(BuildContext context) {
- // pipes are illegal characters in URLs so please
- // - forgive the cheap hack or
- // - refactor by making a custom object and defining equality for it :)
- final sources = drug.userGuideline!.externalData
- .map((data) => '${data.source}|${data.guidelineUrl}')
- .toSet();
- return Column(children: [
- SubHeader(
- context.l10n.drugs_page_header_further_info,
- ),
- SizedBox(height: 12),
- ...sources.map(
- (source) => GestureDetector(
- onTap: () => _launchUrl(Uri.parse(source.split('|')[1])),
- child: Card(
- shape:
- RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
- color: PharMeTheme.onSurfaceColor,
- child: Padding(
- padding: EdgeInsets.all(12),
- child: Row(mainAxisSize: MainAxisSize.min, children: [
- Flexible(
- child: Text(context.l10n
- .drugs_page_sources_description(source.split('|')[0])),
- ),
- Icon(Icons.chevron_right_rounded)
- ]),
- ),
- ),
- ),
- ),
- ]);
- }
-}
-
-Future _launchUrl(Uri url) async {
- if (!await launchUrl(url)) throw Error();
-}
diff --git a/app/lib/common/pages/drug/widgets/module.dart b/app/lib/common/pages/drug/widgets/module.dart
deleted file mode 100644
index a95ff23a8..000000000
--- a/app/lib/common/pages/drug/widgets/module.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-export 'annotation_cards/drug.dart';
-export 'annotation_cards/guideline.dart';
-export 'disclaimer.dart';
-export 'sub_header.dart';
diff --git a/app/lib/common/routing/router.dart b/app/lib/common/routing/router.dart
index 2545fa7f3..95d0bffee 100644
--- a/app/lib/common/routing/router.dart
+++ b/app/lib/common/routing/router.dart
@@ -1,31 +1,34 @@
-import '../../common/module.dart';
+import '../../drug/module.dart';
import '../../drug_selection/module.dart';
import '../../faq/module.dart';
import '../../login/module.dart';
+import '../../main/module.dart';
+import '../../more/module.dart';
import '../../onboarding/module.dart';
import '../../report/module.dart';
import '../../search/module.dart';
-import '../../settings/module.dart';
-import '../pages/main/main.dart';
+import '../module.dart';
part 'router.gr.dart';
-@MaterialAutoRouter(
- replaceInRouteName: 'Page,Route',
- routes: [
- drugSelectionRoutes,
- loginRoutes,
- onboardingRoutes,
- AutoRoute(
- path: 'main',
- page: MainPage,
+@AutoRouterConfig()
+class AppRouter extends _$AppRouter {
+ @override
+ RouteType get defaultRouteType => RouteType.adaptive();
+ @override
+ List get routes => [
+ drugSelectionRoute(),
+ loginRoute(),
+ onboardingRoute(),
+ mainRoute(
children: [
- reportRoutes,
- searchRoutes,
- settingsRoutes,
- faqRoutes,
+ reportRoute(children: [ geneRoute(), drugRoute() ]),
+ searchRoute(children: [ drugRoute() ]),
+ faqRoute(),
+ moreRoute(
+ children: [ aboutRoute(), termsRoute(), privacyRoute() ],
+ ),
],
),
- ],
-)
-class AppRouter extends _$AppRouter {}
+ ];
+}
diff --git a/app/lib/common/services.dart b/app/lib/common/services.dart
index 6f3ee20b6..54d0ae633 100644
--- a/app/lib/common/services.dart
+++ b/app/lib/common/services.dart
@@ -1,7 +1,6 @@
import 'package:hive_flutter/hive_flutter.dart';
-import 'models/drug/cached_drugs.dart';
-import 'models/module.dart';
+import 'module.dart';
Future initServices() async {
await Hive.initFlutter();
diff --git a/app/lib/common/theme.dart b/app/lib/common/theme.dart
index 9011ede43..b49c948bd 100644
--- a/app/lib/common/theme.dart
+++ b/app/lib/common/theme.dart
@@ -81,6 +81,7 @@ class PharMeTheme {
static const backgroundColor = Colors.white;
static const errorColor = Color(0xccf52a2a);
static final borderColor = Colors.black.withOpacity(.2);
+ static final iconColor = darkenColor(PharMeTheme.onSurfaceText, -0.1);
static const smallSpace = 8.0;
static const smallToMediumSpace = 12.0;
@@ -88,6 +89,9 @@ class PharMeTheme {
static const mediumToLargeSpace = 24.0;
static const largeSpace = 32.0;
+ static const outerCardRadius = mediumSpace;
+ static const innerCardRadius = smallToMediumSpace;
+
static final appBarTheme = AppBarTheme(
backgroundColor: surfaceColor,
foregroundColor: onSurfaceText,
diff --git a/app/lib/common/utilities/color_utils.dart b/app/lib/common/utilities/color_utils.dart
index e239cb534..f8450573f 100644
--- a/app/lib/common/utilities/color_utils.dart
+++ b/app/lib/common/utilities/color_utils.dart
@@ -3,7 +3,7 @@ import '../module.dart';
// From https://stackoverflow.com/a/58604669
Color darkenColor(Color color, [double amount = 0.1]) {
- assert(amount >= 0 && amount <= 1);
+ assert(amount >= -1 && amount <= 1);
final hsl = HSLColor.fromColor(color);
final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0));
return hslDark.toColor();
diff --git a/app/lib/common/utilities/drug_utils.dart b/app/lib/common/utilities/drug_utils.dart
index 9cd910351..6620203ef 100644
--- a/app/lib/common/utilities/drug_utils.dart
+++ b/app/lib/common/utilities/drug_utils.dart
@@ -1,9 +1,8 @@
import 'dart:convert';
import 'package:http/http.dart';
-import '../models/drug/cached_drugs.dart';
+import '../../app.dart';
import '../module.dart';
-import '../pages/drug/widgets/adaptive_dialog.dart';
Future updateCachedDrugs() async {
if (UserData.instance.lookups == null) throw Exception();
@@ -33,12 +32,11 @@ Future updateCachedDrugs() async {
// ignore: use_build_context_synchronously
await showAdaptiveDialog(
context: context,
- builder: (context) => AdaptiveAlertDialog(
+ builder: (context) => DialogWrapper(
title: context.l10n.update_warning_title,
- content: Text(context.l10n.update_warning_body),
+ content: DialogContentText(context.l10n.update_warning_body),
actions: [
- AdaptiveDialogAction(
- isDefault: true,
+ DialogAction(
onPressed: () => Navigator.pop(context),
text: context.l10n.action_continue,
),
diff --git a/app/lib/common/utilities/genome_data.dart b/app/lib/common/utilities/genome_data.dart
index 1f8d5f58e..bf9c4a056 100644
--- a/app/lib/common/utilities/genome_data.dart
+++ b/app/lib/common/utilities/genome_data.dart
@@ -4,7 +4,6 @@ import 'dart:convert';
import 'package:http/http.dart';
import '../constants.dart';
-import '../models/drug/cached_drugs.dart';
import '../models/module.dart';
Future fetchAndSaveDiplotypesAndActiveDrugs(
@@ -31,7 +30,9 @@ Future _saveDiplotypeAndActiveDrugsResponse(
diplotypesFromHTTPResponse(response).filterValidDiplotypes();
final activeDrugList = activeDrugsFromHTTPResponse(response);
- UserData.instance.diplotypes = {for (var d in diplotypes) d.gene: d};
+ UserData.instance.diplotypes = {
+ for (final diplotype in diplotypes) diplotype.gene: diplotype
+ };
await UserData.save();
await activeDrugs.setList(activeDrugList);
// invalidate cached drugs because lookups may have changed and we need to
diff --git a/app/lib/common/utilities/module.dart b/app/lib/common/utilities/module.dart
index b7529502e..20e5ed438 100644
--- a/app/lib/common/utilities/module.dart
+++ b/app/lib/common/utilities/module.dart
@@ -1,7 +1,9 @@
+export 'color_utils.dart';
export 'drug_utils.dart';
export 'genome_data.dart';
export 'material_colors.dart';
export 'networking_utils.dart';
+export 'pdf_utils.dart';
export 'platform_utils.dart';
export 'routing_utils.dart';
export 'string_utils.dart';
diff --git a/app/lib/common/utilities/pdf_utils.dart b/app/lib/common/utilities/pdf_utils.dart
index 4d47b4598..750a84494 100644
--- a/app/lib/common/utilities/pdf_utils.dart
+++ b/app/lib/common/utilities/pdf_utils.dart
@@ -332,8 +332,7 @@ List _buildGuidelinePart(
implication.key
),
text: implication.value,
- )))
- .toList(),
+ ))),
_buildTextSpacer(),
_PdfSegment(
child: _PdfDescription(
diff --git a/app/lib/common/utilities/routing_utils.dart b/app/lib/common/utilities/routing_utils.dart
index 2fe94e68a..2bd7d9241 100644
--- a/app/lib/common/utilities/routing_utils.dart
+++ b/app/lib/common/utilities/routing_utils.dart
@@ -1,5 +1,21 @@
import '../module.dart';
+DeepLink getInitialRoute(_) {
+ final isLoggedIn = MetaData.instance.isLoggedIn ?? false;
+ final onboardingDone = MetaData.instance.onboardingDone ?? false;
+ final initialDrugSelectionDone =
+ MetaData.instance.initialDrugSelectionDone ?? false;
+ late String path;
+ path = !isLoggedIn
+ ? '/login'
+ : !onboardingDone
+ ? '/onboarding'
+ : !initialDrugSelectionDone
+ ? '/drugselection'
+ : '/main';
+ return DeepLink.path(path);
+}
+
// Replace whole stack, see https://stackoverflow.com/a/73784156
Future overwriteRoutes(
BuildContext context,
diff --git a/app/lib/common/widgets/checkbox_list_tile_wrapper.dart b/app/lib/common/widgets/checkbox_list_tile_wrapper.dart
new file mode 100644
index 000000000..d01fdd4ab
--- /dev/null
+++ b/app/lib/common/widgets/checkbox_list_tile_wrapper.dart
@@ -0,0 +1,38 @@
+import '../module.dart';
+
+class CheckboxListTileWrapper extends StatelessWidget {
+ const CheckboxListTileWrapper({
+ super.key,
+ required this.title,
+ required this.isChecked,
+ required this.onChanged,
+ this.subtitle,
+ this.isEnabled = true,
+ this.contentPadding,
+ });
+
+ final String title;
+ final String? subtitle;
+ final bool isChecked;
+ // ignore: avoid_positional_boolean_parameters
+ final void Function(bool?)? onChanged;
+ final bool isEnabled;
+ final EdgeInsetsGeometry? contentPadding;
+
+ @override
+ Widget build(BuildContext context) {
+ return ListTile(
+ enabled: isEnabled,
+ title: Text(title, style: PharMeTheme.textTheme.bodyLarge),
+ subtitle: subtitle != null
+ ? Text(subtitle!, style: PharMeTheme.textTheme.bodyMedium)
+ : null,
+ contentPadding: contentPadding,
+ leading: CheckboxWrapper(
+ isEnabled: isEnabled,
+ isChecked: isChecked,
+ onChanged: onChanged,
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/app/lib/common/widgets/checkbox_wrapper.dart b/app/lib/common/widgets/checkbox_wrapper.dart
new file mode 100644
index 000000000..0d2f349a0
--- /dev/null
+++ b/app/lib/common/widgets/checkbox_wrapper.dart
@@ -0,0 +1,28 @@
+import '../module.dart';
+
+class CheckboxWrapper extends StatelessWidget {
+ const CheckboxWrapper({
+ super.key,
+ required this.isChecked,
+ required this.onChanged,
+ this.isEnabled = true,
+ });
+
+ final bool isChecked;
+ // ignore: avoid_positional_boolean_parameters
+ final void Function(bool?)? onChanged;
+ final bool isEnabled;
+
+ @override
+ Widget build(BuildContext context) {
+ return Checkbox.adaptive(
+ value: isChecked,
+ onChanged: isEnabled ? onChanged : null,
+ activeColor: PharMeTheme.primaryColor,
+ checkColor: Colors.white,
+ side: isChecked || !isEnabled
+ ? null
+ : BorderSide(color: darkenColor(PharMeTheme.iconColor, -0.15)),
+ );
+ }
+}
\ No newline at end of file
diff --git a/app/lib/common/widgets/context_menu.dart b/app/lib/common/widgets/context_menu.dart
deleted file mode 100644
index 70ee1a910..000000000
--- a/app/lib/common/widgets/context_menu.dart
+++ /dev/null
@@ -1,132 +0,0 @@
-import 'package:popover/popover.dart';
-
-import '../module.dart';
-
-class ContextMenu extends StatelessWidget {
- const ContextMenu({
- super.key,
- this.headerItem,
- required this.items,
- required this.child,
- });
-
- final Widget? headerItem;
- final List items;
- final Widget child;
-
- @override
- Widget build(BuildContext context) {
- return GestureDetector(
- onTap: () {
- showPopover(
- context: context,
- bodyBuilder: (context) => Padding(
- padding: EdgeInsets.symmetric(
- horizontal: PharMeTheme.smallToMediumSpace
- ),
- child: Container(
- decoration: BoxDecoration(
- color: PharMeTheme.onSurfaceColor,
- borderRadius: BorderRadius.circular(8),
- ),
- child: IntrinsicWidth(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: _buildContent(context),
- ),
- ),
- ),
- ),
- direction: PopoverDirection.bottom,
- arrowHeight: 0,
- arrowWidth: 0,
- transitionDuration: Duration(milliseconds: 100),
- barrierColor: Color.fromRGBO(0, 0, 0, 0.05),
- backgroundColor: Color.fromRGBO(1, 1, 1, 0),
- shadow: [],
- );
- },
- child: child);
- }
-
- Widget _itemContainer(
- Widget item,
- {
- bool showBorder = true,
- double padding = PharMeTheme.smallToMediumSpace,
- }
- ) {
- return Container(
- decoration: showBorder ? BoxDecoration(
- border: Border(
- bottom: BorderSide(
- width: 0.5,
- color: PharMeTheme.borderColor
- ),
- ),
- ) : null,
- child: Padding(
- padding: EdgeInsets.all(padding),
- child: item,
- )
- );
- }
-
- List _buildContent(BuildContext context) {
- final body = items.mapIndexed(
- (index, item) => (index == items.count() - 1)
- ? _itemContainer(item, showBorder: false)
- : _itemContainer(item)
- ).toList();
- return headerItem != null
- ? [
- _itemContainer(
- Row(
- children: [headerItem!]
- ),
- padding: PharMeTheme.mediumSpace,
- showBorder: false,
- ),
- ...body,
- ]
- : body;
- }
-}
-
-class ContextMenuCheckmark extends StatelessWidget {
- const ContextMenuCheckmark(
- {super.key,
- required this.label,
- required this.setState,
- this.initialState = false});
-
- final String label;
- final void Function(bool) setState;
- final bool initialState;
-
- @override
- Widget build(BuildContext context) {
- var state = initialState;
- return StatefulBuilder(
- builder: (context, rebuild) => GestureDetector(
- onTap: () {
- rebuild(() {
- state = !state;
- setState(state);
- });
- },
- child: Row(
- children: [
- if (state)
- Icon(Icons.check_box, size: PharMeTheme.mediumSpace)
- else
- Icon(Icons.check_box_outline_blank, size: PharMeTheme.mediumSpace),
- SizedBox(width: PharMeTheme.smallSpace),
- Expanded(child: Text(label)),
- ],
- ),
- ),
- );
- }
-}
diff --git a/app/lib/common/widgets/dialog_action.dart b/app/lib/common/widgets/dialog_action.dart
new file mode 100644
index 000000000..7c5155dcc
--- /dev/null
+++ b/app/lib/common/widgets/dialog_action.dart
@@ -0,0 +1,37 @@
+import 'package:flutter/cupertino.dart';
+
+import '../module.dart';
+
+class DialogAction extends StatelessWidget {
+ const DialogAction({
+ super.key,
+ this.isDestructive = false,
+ this.onPressed,
+ required this.text,
+ });
+
+ final bool isDestructive;
+ final void Function()? onPressed;
+ final String text;
+
+ @override
+ Widget build(BuildContext context) {
+ switch (getPlatform()) {
+ case SupportedPlatform.ios:
+ return CupertinoDialogAction(
+ isDestructiveAction: isDestructive,
+ onPressed: onPressed,
+ child: Text(text),
+ );
+ default:
+ return TextButton(
+ onPressed: onPressed,
+ child: Text(text, style: onPressed != null
+ ? isDestructive
+ ? TextStyle(color: PharMeTheme.errorColor)
+ : TextStyle(color: PharMeTheme.primaryColor)
+ : TextStyle(color: PharMeTheme.onSurfaceColor)),
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/lib/common/widgets/dialog_content_text.dart b/app/lib/common/widgets/dialog_content_text.dart
new file mode 100644
index 000000000..f3185f360
--- /dev/null
+++ b/app/lib/common/widgets/dialog_content_text.dart
@@ -0,0 +1,14 @@
+import '../module.dart';
+
+class DialogContentText extends StatelessWidget {
+ const DialogContentText(this.text, {
+ super.key,
+ });
+
+ final String text;
+
+ @override
+ Widget build(BuildContext context) {
+ return Text(text, style: PharMeTheme.textTheme.bodyLarge);
+ }
+}
\ No newline at end of file
diff --git a/app/lib/common/widgets/dialog_wrapper.dart b/app/lib/common/widgets/dialog_wrapper.dart
new file mode 100644
index 000000000..b710f4d65
--- /dev/null
+++ b/app/lib/common/widgets/dialog_wrapper.dart
@@ -0,0 +1,31 @@
+import '../module.dart';
+
+class DialogWrapper extends StatelessWidget {
+ const DialogWrapper({
+ super.key,
+ required this.title,
+ required this.content,
+ required this.actions,
+ });
+
+ final String title;
+ final Widget? content;
+ final List actions;
+
+ @override
+ Widget build(BuildContext context) {
+ final materialContent = getPlatform() == SupportedPlatform.ios
+ ? Card(
+ color: Colors.transparent,
+ elevation: 0,
+ child: content,
+ )
+ : content;
+ return AlertDialog.adaptive(
+ title: Text(title),
+ content: materialContent,
+ actions: actions,
+ elevation: 0,
+ );
+ }
+}
diff --git a/app/lib/common/widgets/drug_list/cubit.dart b/app/lib/common/widgets/drug_list/cubit.dart
index e94be55e9..6d20f631f 100644
--- a/app/lib/common/widgets/drug_list/cubit.dart
+++ b/app/lib/common/widgets/drug_list/cubit.dart
@@ -2,7 +2,6 @@ import 'dart:async';
import 'package:freezed_annotation/freezed_annotation.dart';
-import '../../models/drug/cached_drugs.dart';
import '../../module.dart';
part 'cubit.freezed.dart';
diff --git a/app/lib/common/widgets/drug_list/drug_items/drug_cards.dart b/app/lib/common/widgets/drug_list/drug_items/drug_cards.dart
index f44e850ab..dd21c9db0 100644
--- a/app/lib/common/widgets/drug_list/drug_items/drug_cards.dart
+++ b/app/lib/common/widgets/drug_list/drug_items/drug_cards.dart
@@ -33,8 +33,8 @@ class DrugCard extends StatelessWidget {
required this.onTap,
required this.drug,
required this.showDrugInteractionIndicator,
- Key? key,
- }) : super(key: key);
+ super.key,
+ });
final VoidCallback onTap;
final Drug drug;
@@ -43,12 +43,10 @@ class DrugCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final drugName = formatDrugName(drug, showDrugInteractionIndicator);
- return Padding(
- padding: EdgeInsets.symmetric(vertical: PharMeTheme.smallSpace / 2),
- child: RoundedCard(
+ return RoundedCard(
onTap: onTap,
- padding: EdgeInsets.all(8),
- radius: 16,
+ innerPadding: EdgeInsets.all(PharMeTheme.smallSpace * 1.25),
+ radius: 18,
color: drug.warningLevel.color,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -66,15 +64,15 @@ class DrugCard extends StatelessWidget {
.copyWith(fontWeight: FontWeight.bold),
),
]),
- SizedBox(height: 4),
+ SizedBox(height: PharMeTheme.smallSpace / 2),
if (drug.annotations.brandNames.isNotEmpty) ...[
- SizedBox(width: 4),
+ SizedBox(width: PharMeTheme.smallSpace / 2),
Text(
'(${drug.annotations.brandNames.join(', ')})',
style: PharMeTheme.textTheme.titleMedium,
),
],
- SizedBox(height: 8),
+ SizedBox(height: PharMeTheme.smallSpace * 0.75),
Text(
drug.annotations.drugclass,
style: PharMeTheme.textTheme.titleSmall,
@@ -85,7 +83,6 @@ class DrugCard extends StatelessWidget {
Icon(Icons.chevron_right_rounded),
],
),
- ),
);
}
}
diff --git a/app/lib/common/widgets/drug_list/drug_items/drug_checkbox_list.dart b/app/lib/common/widgets/drug_list/drug_items/drug_checkbox_list.dart
index cbffffd57..af81e3452 100644
--- a/app/lib/common/widgets/drug_list/drug_items/drug_checkbox_list.dart
+++ b/app/lib/common/widgets/drug_list/drug_items/drug_checkbox_list.dart
@@ -33,19 +33,19 @@ List buildDrugCheckboxList(
);
return [
SubheaderDivider(
- context.l10n.drug_selection_subheader_active_drugs,
+ text: context.l10n.drug_selection_subheader_active_drugs,
key: Key('header-active'),
),
...activeDrugsList,
SubheaderDivider(
- context.l10n.drug_selection_subheader_all_drugs,
+ text: context.l10n.drug_selection_subheader_all_drugs,
key: Key('header-all'),
),
...allDrugsList,
];
}
-List _buildCheckboxList(
+List _buildCheckboxList(
List drugs,
Map buildParams,
bool showDrugInteractionIndicator,
@@ -54,14 +54,14 @@ List _buildCheckboxList(
final onCheckboxChange = buildParams['onCheckboxChange'];
final checkboxesEnabled = buildParams['checkboxesEnabled'];
return drugs.map(
- (drug) => CheckboxListTile(
+ (drug) => CheckboxListTileWrapper(
key: Key('drug-checkbox-tile-${drug.name}-$keyPrefix'),
- enabled: checkboxesEnabled,
- value: drug.isActive,
+ isEnabled: checkboxesEnabled,
+ isChecked: drug.isActive,
onChanged: (value) => onCheckboxChange(drug, value),
- title: Text(formatDrugName(drug, showDrugInteractionIndicator)),
+ title: formatDrugName(drug, showDrugInteractionIndicator),
subtitle: (drug.annotations.brandNames.isNotEmpty) ?
- Text('(${drug.annotations.brandNames.join(", ")})') :
+ '(${drug.annotations.brandNames.join(", ")})' :
null,
)
).toList();
diff --git a/app/lib/common/widgets/drug_search.dart b/app/lib/common/widgets/drug_search.dart
index fdff3a40c..cc14c956a 100644
--- a/app/lib/common/widgets/drug_search.dart
+++ b/app/lib/common/widgets/drug_search.dart
@@ -3,11 +3,11 @@ import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import '../../../common/module.dart';
-import '../../common/pages/drug/widgets/tooltip_icon.dart';
+import '../../drug/widgets/tooltip_icon.dart';
class DrugSearch extends HookWidget {
DrugSearch({
- Key? key,
+ super.key,
required this.showFilter,
required this.buildDrugItems,
required this.showDrugInteractionIndicator,
@@ -15,8 +15,7 @@ class DrugSearch extends HookWidget {
this.keepPosition = false,
this.drugItemsBuildParams,
DrugListCubit? cubit,
- }) : cubit = cubit ?? DrugListCubit(),
- super(key: key);
+ }) : cubit = cubit ?? DrugListCubit();
final bool showFilter;
final bool useDrugClass;
@@ -66,6 +65,13 @@ class DrugSearch extends HookWidget {
]
),
SizedBox(height: PharMeTheme.smallSpace),
+ if (showDrugInteractionIndicator)
+ PageIndicatorExplanation(
+ context.l10n.search_page_indicator_explanation(
+ drugInteractionIndicatorName,
+ drugInteractionIndicator
+ ),
+ ),
scrollList(
keepPosition: keepPosition,
buildDrugList(
@@ -80,7 +86,6 @@ class DrugSearch extends HookWidget {
useDrugClass: useDrugClass,
)
),
- ..._maybeShowDrugInteractionExplanation(context),
],
);
}
@@ -89,53 +94,42 @@ class DrugSearch extends HookWidget {
);
}
- List _maybeShowDrugInteractionExplanation(BuildContext context) {
- if (!showDrugInteractionIndicator) return [];
- return [
- SizedBox(height: PharMeTheme.smallSpace),
- Text(
- context.l10n.search_page_indicator_explanation(
- drugInteractionIndicatorName,
- drugInteractionIndicator
- )
- ),
- ];
- }
-
Widget buildFilter(BuildContext context) {
final cubit = context.read();
final filter = cubit.filter;
- return ContextMenu(
+ return FilterMenu(
items: [
- ContextMenuCheckmark(
- label: context.l10n.search_page_filter_only_active,
- // Invert state as filter has opposite meaning ('only show active' vs.
- // 'show inactive')
- setState: (state) => cubit.search(showInactive: !state),
- initialState: filter != null && !filter.showInactive),
- ...WarningLevel.values.filter((level) => level != WarningLevel.none)
- .map((level) => ContextMenuCheckmark(
- label: {
+ ...WarningLevel.values
+ .filter((level) => level != WarningLevel.none)
+ .map((level) => FilterMenuItem(
+ title: {
WarningLevel.green: context.l10n.search_page_filter_green,
WarningLevel.yellow: context.l10n.search_page_filter_yellow,
WarningLevel.red: context.l10n.search_page_filter_red,
}[level]!,
- setState: (state) => cubit.search(showWarningLevel: {level: state}),
- initialState: filter?.showWarningLevel[level] ?? false
+ updateSearch: ({ required isChecked }) =>
+ cubit.search(showWarningLevel: { level: isChecked }),
+ isChecked: filter?.showWarningLevel[level] ?? false
)
),
- ContextMenuCheckmark(
- label: context.l10n.search_page_filter_only_with_guidelines,
+ FilterMenuItem(
+ title: context.l10n.search_page_filter_only_active,
+ // Invert state as filter has opposite meaning ('only show active' vs.
+ // 'show inactive')
+ updateSearch: ({ required isChecked }) => cubit.search(showInactive: !isChecked),
+ isChecked: !(filter?.showInactive ?? false)
+ ),
+ FilterMenuItem(
+ title: context.l10n.search_page_filter_only_with_guidelines,
// Invert state as filter has opposite meaning ('show only with
// guidelines' vs. 'show with unknown warning level')
- setState: (state) => cubit.search(
- showWarningLevel: {WarningLevel.none: !state}
+ updateSearch: ({ required isChecked }) => cubit.search(
+ showWarningLevel: { WarningLevel.none: !isChecked }
),
- initialState: filter != null &&
- !filter.showWarningLevel[WarningLevel.none]!,)
+ isChecked: !(filter?.showWarningLevel[WarningLevel.none] ?? false),
+ )
],
- child: Padding(
- padding: EdgeInsets.all(8), child: Icon(Icons.filter_list_rounded)),
+ iconData: Icons.filter_list_rounded,
);
}
}
diff --git a/app/lib/common/widgets/filter_menu.dart b/app/lib/common/widgets/filter_menu.dart
new file mode 100644
index 000000000..06fb25f23
--- /dev/null
+++ b/app/lib/common/widgets/filter_menu.dart
@@ -0,0 +1,57 @@
+import '../module.dart';
+
+class FilterMenuItem {
+ FilterMenuItem({
+ required this.title,
+ required this.updateSearch,
+ required bool isChecked,
+ }) : _isChecked = isChecked;
+
+ final String title;
+ final void Function({ required bool isChecked }) updateSearch;
+ bool _isChecked;
+
+ set checked(newValue) => _isChecked = newValue;
+ bool get checked => _isChecked;
+}
+
+class FilterMenu extends HookWidget {
+ const FilterMenu({
+ super.key,
+ this.headerItem,
+ required this.items,
+ required this.iconData,
+ });
+
+ final Widget? headerItem;
+ final List items;
+ final IconData iconData;
+
+ @override
+ Widget build(BuildContext context) {
+ return PopupMenuButton(
+ icon: Icon(iconData),
+ color: PharMeTheme.onSurfaceColor,
+ elevation: 0,
+ itemBuilder: (context) => items.map(
+ (item) => PopupMenuItem(
+ child: StatefulBuilder(builder: (context, setState) {
+ void toggleCheckbox([_]) {
+ final newValue = !item.checked;
+ setState(() => item.checked = newValue);
+ item.updateSearch(isChecked: newValue);
+ }
+ return ListTile(
+ title: Text(item.title),
+ leading: CheckboxWrapper(
+ isChecked: item.checked,
+ onChanged: toggleCheckbox,
+ ),
+ onTap: toggleCheckbox,
+ );
+ }),
+ )
+ ).toList(),
+ );
+ }
+}
\ No newline at end of file
diff --git a/app/lib/common/widgets/full_width_button.dart b/app/lib/common/widgets/full_width_button.dart
index 79022d9d2..5e73b9dc7 100644
--- a/app/lib/common/widgets/full_width_button.dart
+++ b/app/lib/common/widgets/full_width_button.dart
@@ -4,9 +4,9 @@ class FullWidthButton extends StatelessWidget {
const FullWidthButton(
this.text,
this.action, {
- Key? key,
+ super.key,
this.enabled = true,
- }) : super(key: key);
+ });
final bool enabled;
final String text;
@@ -19,13 +19,10 @@ class FullWidthButton extends StatelessWidget {
child: ElevatedButton(
onPressed: enabled ? action : null,
style: ButtonStyle(
- shape: MaterialStateProperty.all(
- RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(32),
- ),
- ),
+ backgroundColor:
+ MaterialStateProperty.all(PharMeTheme.primaryColor),
),
- child: Text(text),
+ child: Text(text, style: PharMeTheme.textTheme.bodyLarge),
),
);
}
diff --git a/app/lib/common/widgets/headings.dart b/app/lib/common/widgets/headings.dart
index ec83f8a33..8160c8623 100644
--- a/app/lib/common/widgets/headings.dart
+++ b/app/lib/common/widgets/headings.dart
@@ -5,8 +5,8 @@ import '../theme.dart';
class Heading extends StatelessWidget {
const Heading(
this.text, {
- Key? key,
- }) : super(key: key);
+ super.key,
+ });
final String text;
diff --git a/app/lib/common/widgets/module.dart b/app/lib/common/widgets/module.dart
index 70359f7f3..0da919361 100644
--- a/app/lib/common/widgets/module.dart
+++ b/app/lib/common/widgets/module.dart
@@ -1,9 +1,14 @@
-export 'app.dart';
-export 'context_menu.dart';
+export 'checkbox_list_tile_wrapper.dart';
+export 'checkbox_wrapper.dart';
+export 'dialog_action.dart';
+export 'dialog_content_text.dart';
+export 'dialog_wrapper.dart';
export 'drug_list/builder.dart';
export 'drug_list/cubit.dart';
+export 'filter_menu.dart';
export 'headings.dart';
export 'indicators.dart';
+export 'page_indicator_explanation.dart';
export 'page_scaffold.dart';
export 'radiant_gradient_mask.dart';
export 'rounded_card.dart';
diff --git a/app/lib/common/widgets/page_indicator_explanation.dart b/app/lib/common/widgets/page_indicator_explanation.dart
new file mode 100644
index 000000000..522788879
--- /dev/null
+++ b/app/lib/common/widgets/page_indicator_explanation.dart
@@ -0,0 +1,19 @@
+import '../module.dart';
+
+class PageIndicatorExplanation extends StatelessWidget {
+ const PageIndicatorExplanation(this.text);
+
+ final String text;
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: EdgeInsets.only(
+ left: PharMeTheme.smallSpace,
+ right: PharMeTheme.smallSpace,
+ bottom: PharMeTheme.smallSpace,
+ ),
+ child: Text(text),
+ );
+ }
+}
\ No newline at end of file
diff --git a/app/lib/common/widgets/page_scaffold.dart b/app/lib/common/widgets/page_scaffold.dart
index cbdf87860..d01d2b01c 100644
--- a/app/lib/common/widgets/page_scaffold.dart
+++ b/app/lib/common/widgets/page_scaffold.dart
@@ -9,6 +9,7 @@ AppBar? buildBarBottom(String? barBottom) {
? null
: AppBar(
automaticallyImplyLeading: false,
+ scrolledUnderElevation: 0,
backgroundColor: PharMeTheme.appBarTheme.backgroundColor,
elevation: PharMeTheme.appBarTheme.elevation,
title: RichText(
@@ -35,6 +36,7 @@ Scaffold pageScaffold({
key: key,
body: CustomScrollView(slivers: [
SliverAppBar(
+ scrolledUnderElevation: 0,
backgroundColor: PharMeTheme.appBarTheme.backgroundColor,
foregroundColor: PharMeTheme.appBarTheme.foregroundColor,
elevation: PharMeTheme.appBarTheme.elevation,
@@ -71,6 +73,7 @@ Scaffold unscrollablePageScaffold({
title: buildTitle(title),
actions: actions,
bottom: buildBarBottom(barBottom),
+ scrolledUnderElevation: 0,
);
return Scaffold(
key: key,
diff --git a/app/lib/common/widgets/rounded_card.dart b/app/lib/common/widgets/rounded_card.dart
index 7436bf301..9c89f6b92 100644
--- a/app/lib/common/widgets/rounded_card.dart
+++ b/app/lib/common/widgets/rounded_card.dart
@@ -2,42 +2,50 @@ import '../module.dart';
class RoundedCard extends StatelessWidget {
const RoundedCard({
- this.padding = const EdgeInsets.all(16),
- this.color = PharMeTheme.surfaceColor,
- this.radius = 20,
+ this.innerPadding,
+ this.outerVerticalPadding,
+ this.outerHorizontalPadding,
+ this.color,
+ this.radius,
this.onTap,
required this.child,
+ super.key,
});
- final EdgeInsets padding;
+ final EdgeInsets? innerPadding;
+ final double? outerVerticalPadding;
+ final double? outerHorizontalPadding;
final VoidCallback? onTap;
- final Color color;
- final double radius;
+ final Color? color;
+ final double? radius;
final Widget child;
@override
Widget build(BuildContext context) {
- Widget child = Padding(padding: padding, child: this.child);
+ Widget child = Padding(
+ padding: innerPadding ?? EdgeInsets.all(PharMeTheme.smallToMediumSpace),
+ child: this.child,
+ );
if (onTap != null) child = InkWell(onTap: onTap, child: child);
// ignore: sized_box_for_whitespace
return Container(
width: double.infinity,
- child: DecoratedBox(
- decoration: BoxDecoration(
- color: color,
- border: Border.all(width: 0.5, color: PharMeTheme.borderColor),
- borderRadius: BorderRadius.all(Radius.circular(radius)),
- boxShadow: [
- BoxShadow(
- color: PharMeTheme.onSurfaceColor,
- blurRadius: 16,
- offset: Offset(0, 4),
+ child: Padding(
+ padding: EdgeInsets.symmetric(
+ vertical: outerVerticalPadding ?? PharMeTheme.smallSpace * 0.65,
+ horizontal: outerHorizontalPadding ?? PharMeTheme.smallSpace,
+ ),
+ child: DecoratedBox(
+ decoration: BoxDecoration(
+ color: color ?? darkenColor(PharMeTheme.onSurfaceColor, -0.05),
+ borderRadius: BorderRadius.all(
+ Radius.circular(radius ?? PharMeTheme.outerCardRadius)
),
- ],
+ ),
+ child: child,
),
- child: child,
),
);
}
diff --git a/app/lib/common/widgets/scroll_list.dart b/app/lib/common/widgets/scroll_list.dart
index 28796bce6..d96425a0e 100644
--- a/app/lib/common/widgets/scroll_list.dart
+++ b/app/lib/common/widgets/scroll_list.dart
@@ -2,7 +2,10 @@ import 'package:flutter_list_view/flutter_list_view.dart';
import '../module.dart';
-Widget scrollList(List body, {bool keepPosition = false}) {
+Widget scrollList(List body, {
+ bool keepPosition = false,
+ double? verticalPadding,
+}) {
String getItemKey(Widget widget) => widget.key.toString();
if (body.map(getItemKey).toSet().length != body.length) {
throw Exception('Items passed to scrollList need unique keys');
@@ -12,10 +15,24 @@ Widget scrollList(List body, {bool keepPosition = false}) {
thumbVisibility: true,
thickness: PharMeTheme.smallSpace / 2,
child: Padding(
- padding: EdgeInsets.only(right: PharMeTheme.smallSpace * 1.5),
+ padding: EdgeInsets.only(right: PharMeTheme.mediumSpace),
child: FlutterListView(
delegate: FlutterListViewDelegate(
- (context, index) => body[index],
+ (context, index) => (index == 0)
+ ? Padding(
+ padding: EdgeInsets.only(
+ top: verticalPadding ?? PharMeTheme.smallSpace,
+ ),
+ child: body[index]
+ )
+ : (index == body.length - 1)
+ ? Padding(
+ padding: EdgeInsets.only(
+ bottom: verticalPadding ?? PharMeTheme.smallSpace,
+ ),
+ child: body[index]
+ )
+ : body[index],
childCount: body.length,
onItemKey: (index) => getItemKey(body[index]),
keepPosition: keepPosition,
diff --git a/app/lib/common/widgets/subheader_divider.dart b/app/lib/common/widgets/subheader_divider.dart
index bddbaee93..c908bc80a 100644
--- a/app/lib/common/widgets/subheader_divider.dart
+++ b/app/lib/common/widgets/subheader_divider.dart
@@ -1,16 +1,18 @@
import '../module.dart';
class SubheaderDivider extends StatelessWidget {
- const SubheaderDivider(
- this.text, {
+ const SubheaderDivider({
+ this.text = '',
this.indent = 20.0,
this.color,
- Key? key,
- }) : super(key: key);
+ this.useLine = true,
+ super.key,
+ });
final String text;
final double indent;
final Color? color;
+ final bool useLine;
@override
Widget build(BuildContext context) {
@@ -20,7 +22,7 @@ class SubheaderDivider extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Divider(color: widgetColor),
+ if (useLine) Divider(color: widgetColor, thickness: 0.5),
Text(
text,
style:
diff --git a/app/lib/common/pages/drug/cubit.dart b/app/lib/drug/cubit.dart
similarity index 93%
rename from app/lib/common/pages/drug/cubit.dart
rename to app/lib/drug/cubit.dart
index 1a92b593a..a2a39cd3b 100644
--- a/app/lib/common/pages/drug/cubit.dart
+++ b/app/lib/drug/cubit.dart
@@ -3,8 +3,7 @@ import 'dart:async';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:overlay_dialog/overlay_dialog.dart';
-import '../../module.dart';
-import '../../utilities/pdf_utils.dart';
+import '../common/module.dart';
part 'cubit.freezed.dart';
diff --git a/app/lib/drug/module.dart b/app/lib/drug/module.dart
new file mode 100644
index 000000000..ea729c361
--- /dev/null
+++ b/app/lib/drug/module.dart
@@ -0,0 +1,8 @@
+import '../common/module.dart';
+
+// For generated routes
+export 'cubit.dart';
+export 'pages/drug.dart';
+
+// Used by multiple parent routes, therefore returning function for creation
+AutoRoute drugRoute() => AutoRoute(page: DrugRoute.page);
\ No newline at end of file
diff --git a/app/lib/common/pages/drug/drug.dart b/app/lib/drug/pages/drug.dart
similarity index 81%
rename from app/lib/common/pages/drug/drug.dart
rename to app/lib/drug/pages/drug.dart
index 1ffed21d2..07cbad2fd 100644
--- a/app/lib/common/pages/drug/drug.dart
+++ b/app/lib/drug/pages/drug.dart
@@ -1,9 +1,10 @@
import 'package:provider/provider.dart';
-import '../../module.dart';
-import 'cubit.dart';
-import 'widgets/module.dart';
+import '../../common/module.dart';
+import '../cubit.dart';
+import '../widgets/module.dart';
+@RoutePage()
class DrugPage extends StatelessWidget {
const DrugPage(
this.drug, {
@@ -49,25 +50,19 @@ class DrugPage extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- SubHeader(context.l10n.drugs_page_header_drug),
- SizedBox(height: 12),
DrugAnnotationCard(
drug,
isActive: drug.isActive,
- setActivity: (value) =>
+ setActivity: ({ value }) =>
context.read().setActivity(drug, value),
disabled: loading,
),
- SizedBox(height: 20),
+ SizedBox(height: PharMeTheme.mediumSpace),
SubHeader(
context.l10n.drugs_page_header_guideline,
tooltip: context.l10n.drugs_page_tooltip_guideline,
),
- SizedBox(height: 12),
- if (drug.userGuideline != null) ...[
- Disclaimer(),
- SizedBox(height: 12),
- ],
+ SizedBox(height: PharMeTheme.smallSpace),
GuidelineAnnotationCard(drug),
],
),
diff --git a/app/lib/drug/widgets/annotation_cards/annotation_table.dart b/app/lib/drug/widgets/annotation_cards/annotation_table.dart
new file mode 100644
index 000000000..82835f7fc
--- /dev/null
+++ b/app/lib/drug/widgets/annotation_cards/annotation_table.dart
@@ -0,0 +1,42 @@
+import '../../../common/module.dart';
+
+class TableRowDefinition {
+ const TableRowDefinition(this.key, this.value);
+ final String key;
+ final String value;
+}
+
+Table buildTable(
+ List rowDefinitions,
+ {
+ TextStyle? style,
+ }
+) {
+ return Table(
+ defaultColumnWidth: IntrinsicColumnWidth(),
+ children: rowDefinitions.map((rowDefinition) => _buildRow(
+ rowDefinition.key,
+ rowDefinition.value,
+ style ?? PharMeTheme.textTheme.bodyMedium!,
+ )).toList(),
+ );
+}
+
+TableRow _buildRow(
+ String key,
+ String value,
+ TextStyle textStyle,
+) {
+ return TableRow(
+ children: [
+ Padding(
+ padding: EdgeInsets.only(right: PharMeTheme.smallSpace),
+ child: Text(
+ key,
+ style: textStyle.copyWith(fontWeight: FontWeight.bold),
+ ),
+ ),
+ Text(value, style: textStyle),
+ ],
+ );
+}
\ No newline at end of file
diff --git a/app/lib/common/pages/drug/widgets/disclaimer.dart b/app/lib/drug/widgets/annotation_cards/disclaimer.dart
similarity index 66%
rename from app/lib/common/pages/drug/widgets/disclaimer.dart
rename to app/lib/drug/widgets/annotation_cards/disclaimer.dart
index bff430eab..c463fb26e 100644
--- a/app/lib/common/pages/drug/widgets/disclaimer.dart
+++ b/app/lib/drug/widgets/annotation_cards/disclaimer.dart
@@ -1,7 +1,4 @@
-import 'package:flutter/material.dart';
-
-import '../../../l10n.dart';
-import '../../../theme.dart';
+import '../../../common/module.dart';
class Disclaimer extends StatelessWidget {
const Disclaimer({this.text});
@@ -11,24 +8,26 @@ class Disclaimer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
- padding: EdgeInsets.all(4),
+ padding: EdgeInsets.all(PharMeTheme.smallSpace),
decoration: BoxDecoration(
- borderRadius: BorderRadius.all(Radius.circular(8)),
+ borderRadius: BorderRadius.all(
+ Radius.circular(PharMeTheme.innerCardRadius * 0.75)
+ ),
color: PharMeTheme.surfaceColor,
border: Border.all(color: PharMeTheme.errorColor, width: 1.2),
),
child: Row(children: [
Icon(
Icons.warning_rounded,
- size: 52,
+ size: PharMeTheme.largeSpace,
color: PharMeTheme.errorColor,
),
- SizedBox(width: 8),
+ SizedBox(width: PharMeTheme.smallSpace),
Flexible(
child: Text(
text ?? context.l10n.drugs_page_disclaimer,
style: PharMeTheme.textTheme.labelMedium!.copyWith(
- fontWeight: FontWeight.w100,
+ fontWeight: FontWeight.w300,
),
),
),
diff --git a/app/lib/drug/widgets/annotation_cards/drug.dart b/app/lib/drug/widgets/annotation_cards/drug.dart
new file mode 100644
index 000000000..6dfbac36e
--- /dev/null
+++ b/app/lib/drug/widgets/annotation_cards/drug.dart
@@ -0,0 +1,123 @@
+import '../../../common/module.dart';
+import '../sub_header.dart';
+import 'annotation_table.dart';
+
+class DrugAnnotationCard extends StatelessWidget {
+ const DrugAnnotationCard(
+ this.drug, {
+ required this.isActive,
+ required this.setActivity,
+ this.disabled = false,
+ });
+
+ final Drug drug;
+ final bool isActive;
+ final void Function({ bool? value }) setActivity;
+ final bool disabled;
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ SubHeader(context.l10n.drugs_page_header_drug),
+ SizedBox(height: PharMeTheme.smallSpace),
+ RoundedCard(
+ innerPadding: EdgeInsets.all(PharMeTheme.mediumSpace),
+ child: SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(drug.annotations.indication),
+ SizedBox(height: PharMeTheme.smallSpace),
+ buildTable([
+ TableRowDefinition(
+ context.l10n.drugs_page_header_drugclass,
+ drug.annotations.drugclass,
+ ),
+ if (drug.annotations.brandNames.isNotEmpty)
+ TableRowDefinition(
+ context.l10n.drugs_page_header_synonyms,
+ drug.annotations.brandNames.join(', '),
+ ),
+ ]),
+ if (isInhibitor(drug.name)) ...[
+ SizedBox(height: 8),
+ Text(context.l10n.drugs_page_is_inhibitor(
+ drug.name,
+ inhibitedGenes(drug).join(', '),
+ )),
+ ],
+ ],
+ ),
+ ),
+ ),
+ SizedBox(height: PharMeTheme.mediumSpace),
+ SubHeader(context.l10n.drugs_page_header_active),
+ SizedBox(height: PharMeTheme.smallSpace),
+ RoundedCard(
+ innerPadding: EdgeInsets.all(PharMeTheme.smallSpace),
+ child: Padding(
+ padding: EdgeInsets.symmetric(horizontal: PharMeTheme.smallSpace),
+ child: DropdownButton(
+ value: isActive,
+ isExpanded: true,
+ icon: const Icon(Icons.expand_more),
+ onChanged: disabled ? null : (newValue) => {
+ if (isInhibitor(drug.name)) {
+ showAdaptiveDialog(
+ context: context,
+ builder: (context) => DialogWrapper(
+ title: context.l10n.drugs_page_active_warn_header,
+ content: DialogContentText(
+ context.l10n.drugs_page_active_warn,
+ ),
+ actions: [
+ DialogAction(
+ onPressed: () => Navigator.pop(context, 'Cancel'),
+ text: context.l10n.action_cancel,
+ ),
+ DialogAction(
+ onPressed: () {
+ Navigator.pop(context, 'OK');
+ setActivity(value: newValue);
+ },
+ text: context.l10n.action_continue,
+ isDestructive: true,
+ ),
+ ],
+ ),
+ )
+ } else {
+ setActivity(value: newValue)
+ }
+ },
+ items: [
+ DropdownMenuItem(
+ value: true,
+ child: Row(
+ children: [
+ Icon(
+ Icons.check_circle_outline,
+ color: PharMeTheme.iconColor,
+ ),
+ SizedBox(width: PharMeTheme.smallSpace),
+ Text(context.l10n.drugs_page_active),
+ ]),
+ ),
+ DropdownMenuItem(
+ value: false,
+ child: Row(
+ children: [
+ Icon(Icons.cancel_outlined, color: PharMeTheme.iconColor),
+ SizedBox(width: PharMeTheme.smallSpace),
+ Text(context.l10n.drugs_page_inactive),
+ ]),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/app/lib/drug/widgets/annotation_cards/guideline.dart b/app/lib/drug/widgets/annotation_cards/guideline.dart
new file mode 100644
index 000000000..3f891be17
--- /dev/null
+++ b/app/lib/drug/widgets/annotation_cards/guideline.dart
@@ -0,0 +1,136 @@
+import 'package:url_launcher/url_launcher.dart';
+
+import '../../../common/module.dart';
+import '../module.dart';
+
+class GuidelineAnnotationCard extends StatelessWidget {
+ const GuidelineAnnotationCard(this.drug);
+
+ final Drug drug;
+
+ @override
+ Widget build(BuildContext context) {
+ return RoundedCard(
+ innerPadding: const EdgeInsets.all(PharMeTheme.mediumSpace),
+ child: SingleChildScrollView(
+ child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
+ if (drug.guidelines.isNotEmpty) ...[
+ _buildHeader(context),
+ SizedBox(height: PharMeTheme.mediumSpace),
+ _buildCard(context),
+ SizedBox(height: PharMeTheme.mediumSpace),
+ _buildSourcesSection(context),
+ ]
+ else ...[
+ _buildHeader(context),
+ SizedBox(height: PharMeTheme.smallSpace),
+ _buildCard(context),
+ ],
+ ]),
+ ),
+ );
+ }
+
+ Widget _buildCard(BuildContext context) {
+ final upperCardText = drug.userGuideline?.annotations.implication ??
+ context.l10n.drugs_page_no_guidelines_for_phenotype_implication(
+ drug.name
+ );
+ final lowerCardText = drug.userGuideline?.annotations.recommendation ??
+ context.l10n.drugs_page_no_guidelines_for_phenotype_recommendation;
+ return RoundedCard(
+ key: Key('annotationCard'),
+ radius: PharMeTheme.innerCardRadius,
+ outerHorizontalPadding: 0,
+ outerVerticalPadding: 0,
+ color: drug.warningLevel.color,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(children: [
+ Icon(
+ drug.warningLevel.icon,
+ color: PharMeTheme.onSurfaceText,
+ size: PharMeTheme.largeSpace,
+ ),
+ SizedBox(width: PharMeTheme.smallToMediumSpace),
+ Flexible(
+ child: Text(
+ upperCardText,
+ style: PharMeTheme.textTheme.bodyMedium,
+ ),
+ )
+ ]),
+ SizedBox(height: PharMeTheme.smallToMediumSpace),
+ Text(
+ lowerCardText,
+ style: PharMeTheme.textTheme.bodyMedium,
+ ),
+ if (drug.userGuideline != null) ...[
+ SizedBox(height: PharMeTheme.smallToMediumSpace),
+ Disclaimer(),
+ ],
+ ]
+ )
+ );
+ }
+
+ Widget _buildHeader(BuildContext context) {
+ if (drug.userGuideline == null && drug.guidelines.isEmpty) {
+ return Text(
+ context.l10n.drugs_page_guidelines_empty(drug.name),
+ style: TextStyle(fontStyle: FontStyle.italic),
+ );
+ } else {
+ final genes = drug.userGuideline?.lookupkey.keys ??
+ drug.guidelines.first.lookupkey.keys;
+ final geneDescriptions = genes.map((geneSymbol) {
+ final phenotypeInformation = UserData.phenotypeFor(
+ geneSymbol,
+ context,
+ drug: drug.name,
+ );
+ var description = phenotypeInformation.phenotype;
+ if (phenotypeInformation.adaptionText.isNotNullOrBlank) {
+ description = '$description (${phenotypeInformation.adaptionText})';
+ }
+ return TableRowDefinition(geneSymbol, description);
+ });
+ return buildTable(geneDescriptions.toList());
+ }
+ }
+
+ Widget _buildSourcesSection(BuildContext context) {
+ // pipes are illegal characters in URLs so please
+ // - forgive the cheap hack or
+ // - refactor by making a custom object and defining equality for it :)
+ final guideline = drug.userGuideline ?? drug.guidelines.first;
+ final sources = guideline.externalData
+ .map((data) => '${data.source}|${data.guidelineUrl}')
+ .toSet();
+ return Column(children: [
+ ...sources.map(
+ (source) => GestureDetector(
+ onTap: () => _launchUrl(Uri.parse(source.split('|')[1])),
+ child: RoundedCard(
+ radius: PharMeTheme.innerCardRadius,
+ outerHorizontalPadding: 0,
+ outerVerticalPadding: 0,
+ color: darkenColor(PharMeTheme.onSurfaceColor, 0.05),
+ child: Row(mainAxisSize: MainAxisSize.min, children: [
+ Flexible(
+ child: Text(context.l10n
+ .drugs_page_sources_description(source.split('|')[0])),
+ ),
+ Icon(Icons.chevron_right_rounded)
+ ])
+ ),
+ ),
+ ),
+ ]);
+ }
+}
+
+Future _launchUrl(Uri url) async {
+ if (!await launchUrl(url)) throw Error();
+}
diff --git a/app/lib/drug/widgets/module.dart b/app/lib/drug/widgets/module.dart
new file mode 100644
index 000000000..c79aef87d
--- /dev/null
+++ b/app/lib/drug/widgets/module.dart
@@ -0,0 +1,6 @@
+export 'annotation_cards/annotation_table.dart';
+export 'annotation_cards/disclaimer.dart';
+export 'annotation_cards/drug.dart';
+export 'annotation_cards/guideline.dart';
+export 'sub_header.dart';
+export 'tooltip_icon.dart';
diff --git a/app/lib/common/pages/drug/widgets/source_card.dart b/app/lib/drug/widgets/source_card.dart
similarity index 91%
rename from app/lib/common/pages/drug/widgets/source_card.dart
rename to app/lib/drug/widgets/source_card.dart
index e2d284756..cf82036a5 100644
--- a/app/lib/common/pages/drug/widgets/source_card.dart
+++ b/app/lib/drug/widgets/source_card.dart
@@ -1,7 +1,5 @@
-import 'package:auto_size_text/auto_size_text.dart';
-import 'package:flutter/material.dart';
+import '../../common/module.dart';
-import '../../../theme.dart';
class SourceCard extends StatelessWidget {
const SourceCard({
diff --git a/app/lib/common/pages/drug/widgets/sub_header.dart b/app/lib/drug/widgets/sub_header.dart
similarity index 84%
rename from app/lib/common/pages/drug/widgets/sub_header.dart
rename to app/lib/drug/widgets/sub_header.dart
index 5f589f960..ea3913bb4 100644
--- a/app/lib/common/pages/drug/widgets/sub_header.dart
+++ b/app/lib/drug/widgets/sub_header.dart
@@ -1,7 +1,4 @@
-import 'package:dartx/dartx.dart';
-import 'package:flutter/material.dart';
-
-import '../../../theme.dart';
+import '../../common/module.dart';
import 'tooltip_icon.dart';
class SubHeader extends StatelessWidget {
diff --git a/app/lib/common/pages/drug/widgets/tooltip_icon.dart b/app/lib/drug/widgets/tooltip_icon.dart
similarity index 100%
rename from app/lib/common/pages/drug/widgets/tooltip_icon.dart
rename to app/lib/drug/widgets/tooltip_icon.dart
diff --git a/app/lib/drug_selection/cubit.dart b/app/lib/drug_selection/cubit.dart
new file mode 100644
index 000000000..4d0af2c30
--- /dev/null
+++ b/app/lib/drug_selection/cubit.dart
@@ -0,0 +1,26 @@
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+import '../../common/module.dart';
+
+part 'cubit.freezed.dart';
+
+class DrugSelectionCubit extends Cubit {
+ DrugSelectionCubit(this.activeDrugs) :
+ super(DrugSelectionState.stable());
+
+ final ActiveDrugs activeDrugs;
+
+ // ignore: avoid_positional_boolean_parameters
+ Future updateDrugActivity(Drug drug, bool? value) async {
+ if (value == null) return;
+ emit(DrugSelectionState.updating());
+ await activeDrugs.changeActivity(drug.name, value);
+ emit(DrugSelectionState.stable());
+ }
+}
+
+@freezed
+class DrugSelectionState with _$DrugSelectionState {
+ const factory DrugSelectionState.stable() = _StableState;
+ const factory DrugSelectionState.updating() = _UpdatingState;
+}
diff --git a/app/lib/drug_selection/module.dart b/app/lib/drug_selection/module.dart
index 2a63e7106..1b00a4161 100644
--- a/app/lib/drug_selection/module.dart
+++ b/app/lib/drug_selection/module.dart
@@ -1,12 +1,10 @@
import '../common/module.dart';
-import 'pages/drug_selection.dart';
-// We need to expose all pages for AutoRouter
-export 'pages/cubit.dart';
+// For generated route
+export 'cubit.dart';
export 'pages/drug_selection.dart';
-const drugSelectionRoutes = AutoRoute(
- path: 'drugselection',
- name: 'DrugSelectionRouter',
- page: DrugSelectionPage,
-);
+AutoRoute drugSelectionRoute() => AutoRoute(
+ path: '/drugselection',
+ page: DrugSelectionRoute.page,
+);
\ No newline at end of file
diff --git a/app/lib/drug_selection/pages/cubit.dart b/app/lib/drug_selection/pages/cubit.dart
deleted file mode 100644
index 2ae4f0e2d..000000000
--- a/app/lib/drug_selection/pages/cubit.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-import 'package:freezed_annotation/freezed_annotation.dart';
-
-import '../../../common/module.dart';
-
-part 'cubit.freezed.dart';
-
-class DrugSelectionPageCubit extends Cubit {
- DrugSelectionPageCubit(this.activeDrugs) :
- super(DrugSelectionPageState.stable());
-
- final ActiveDrugs activeDrugs;
-
- // ignore: avoid_positional_boolean_parameters
- Future updateDrugActivity(Drug drug, bool? value) async {
- if (value == null) return;
- emit(DrugSelectionPageState.updating());
- await activeDrugs.changeActivity(drug.name, value);
- emit(DrugSelectionPageState.stable());
- }
-}
-
-@freezed
-class DrugSelectionPageState with _$DrugSelectionPageState {
- const factory DrugSelectionPageState.stable() = _StableState;
- const factory DrugSelectionPageState.updating() = _UpdatingState;
-}
diff --git a/app/lib/drug_selection/pages/drug_selection.dart b/app/lib/drug_selection/pages/drug_selection.dart
index d4d07a6fe..ff5b692a5 100644
--- a/app/lib/drug_selection/pages/drug_selection.dart
+++ b/app/lib/drug_selection/pages/drug_selection.dart
@@ -1,36 +1,36 @@
import 'package:provider/provider.dart';
-import '../../common/models/drug/cached_drugs.dart';
import '../../common/models/metadata.dart';
import '../../common/module.dart' hide MetaData;
import '../../common/widgets/drug_list/drug_items/drug_checkbox_list.dart';
import '../../common/widgets/drug_search.dart';
import '../../common/widgets/full_width_button.dart';
-import 'cubit.dart';
+import '../cubit.dart';
+@RoutePage()
class DrugSelectionPage extends HookWidget {
const DrugSelectionPage({
- Key? key,
+ super.key,
this.concludesOnboarding = true,
@visibleForTesting this.cubit,
- }) : super(key: key);
+ });
- final DrugSelectionPageCubit? cubit;
+ final DrugSelectionCubit? cubit;
final bool concludesOnboarding;
@override
Widget build(BuildContext context) {
return Consumer(
builder: (context, activeDrugs, child) => BlocProvider(
- create: (context) => cubit ?? DrugSelectionPageCubit(activeDrugs),
- child: BlocBuilder(
+ create: (context) => cubit ?? DrugSelectionCubit(activeDrugs),
+ child: BlocBuilder(
builder: (context, state) {
return unscrollablePageScaffold(
title: context.l10n.drug_selection_header,
barBottom: concludesOnboarding
? context.l10n.drug_selection_onboarding_description
: null,
- padding: PharMeTheme.largeSpace,
+ padding: PharMeTheme.mediumSpace,
body: Column(
children: [
Expanded(child: _buildDrugList(context, state)),
@@ -44,16 +44,20 @@ class DrugSelectionPage extends HookWidget {
);
}
- bool _isEditable(DrugSelectionPageState state) {
+ bool _isEditable(DrugSelectionState state) {
return state.when(
stable: () => true,
updating: () => false
);
}
- Widget _buildButton(BuildContext context, DrugSelectionPageState state) {
+ Widget _buildButton(BuildContext context, DrugSelectionState state) {
return Padding(
- padding: EdgeInsets.only(top: PharMeTheme.mediumSpace),
+ padding: EdgeInsets.only(
+ left: PharMeTheme.mediumSpace,
+ top: PharMeTheme.mediumSpace,
+ right: PharMeTheme.mediumSpace,
+ ),
child: FullWidthButton(
context.l10n.action_continue,
() async {
@@ -67,7 +71,7 @@ class DrugSelectionPage extends HookWidget {
);
}
- Widget _buildDrugList(BuildContext context, DrugSelectionPageState state) {
+ Widget _buildDrugList(BuildContext context, DrugSelectionState state) {
if (CachedDrugs.instance.drugs!.isEmpty) {
return Column(
children: [
@@ -88,7 +92,7 @@ class DrugSelectionPage extends HookWidget {
drugItemsBuildParams: {
'checkboxesEnabled': _isEditable(state),
'onCheckboxChange': (drug, value) => context
- .read()
+ .read()
.updateDrugActivity(drug, value),
},
showDrugInteractionIndicator: false,
diff --git a/app/lib/faq/module.dart b/app/lib/faq/module.dart
index 804e253c6..38c656133 100644
--- a/app/lib/faq/module.dart
+++ b/app/lib/faq/module.dart
@@ -1,11 +1,6 @@
import '../common/module.dart';
-import 'pages/faq.dart';
-// We need to expose all pages for AutoRouter
+// For generated routes
export 'pages/faq.dart';
-const faqRoutes = AutoRoute(
- path: 'faq',
- name: 'FaqRouter',
- page: FaqPage,
-);
+AutoRoute faqRoute() => AutoRoute(path: 'faq', page: FaqRoute.page);
\ No newline at end of file
diff --git a/app/lib/faq/pages/faq.dart b/app/lib/faq/pages/faq.dart
index cdc7f668b..3905c7eec 100644
--- a/app/lib/faq/pages/faq.dart
+++ b/app/lib/faq/pages/faq.dart
@@ -1,74 +1,97 @@
import '../../common/module.dart';
import '../constants.dart';
+@RoutePage()
class FaqPage extends StatelessWidget {
- const FaqPage({Key? key}) : super(key: key);
+ const FaqPage({super.key});
@override
Widget build(BuildContext context) {
- return WillPopScope(
+ return PopScope(
+ canPop: false,
child: pageScaffold(title: context.l10n.tab_faq, body: [
Padding(
- padding: const EdgeInsets.all(8),
+ padding: const EdgeInsets.all(PharMeTheme.smallSpace),
child: Column(
key: Key('questionsColumn'),
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 8),
...faqList.keys.fold>(
[], (widgets, topic) =>
[...widgets, ..._buildTopic(context, topic, faqList[topic]!)]
),
- Divider(),
- ListTile(
+ ..._buildTopicHeader(
+ context.l10n.settings_page_contact_us,
+ addSpace: true,
+ ),
+ _buildQuestionCard(
+ child: ListTile(
title: Text(context.l10n.faq_contact_us),
trailing: Icon(Icons.chevron_right_rounded),
- onTap: sendEmail)
+ iconColor: PharMeTheme.iconColor,
+ onTap: sendEmail
+ )
+ )
+
],
),
),
]),
- onWillPop: () async => false,
);
}
+ List _buildTopicHeader(String title, { required bool addSpace }) => [
+ if (addSpace) SizedBox(height: PharMeTheme.mediumSpace),
+ SubheaderDivider(text: title, useLine: false),
+ ];
+
+ Widget _buildQuestionCard({ required Widget child, Key? key }) => RoundedCard(
+ key: key,
+ innerPadding: EdgeInsets.all(PharMeTheme.smallSpace * 0.25),
+ child: child,
+ );
+
List _buildTopic(
BuildContext context,
String topicName,
List questions
) {
+ final topicIndex = faqList.keys.toList().indexOf(topicName);
return [
- ListTile(
- title: Text(
- topicName,
- style: PharMeTheme.textTheme.bodyMedium,
- ),
- dense: true,
- ),
- ...questions.map((question) => _buildQuestion(context, question)).toList()
+ ..._buildTopicHeader(topicName, addSpace: topicIndex != 0),
+ ...questions.map((question) => _buildQuestion(context, question))
];
}
Widget _buildQuestion(BuildContext context, Question question) {
final key = GlobalKey();
-
- return Card(
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(16),
- ),
- child: ExpansionTile(
- key: key,
- title: Text(question.question),
- onExpansionChanged: (value) {
- if (value) _scrollToSelectedContent(key: key);
- },
- children: [
- ListTile(
- contentPadding: EdgeInsets.only(left: 16, right: 16, bottom: 8),
- title: Text(question.answer),
+ return _buildQuestionCard(
+ key: key,
+ child: Theme(
+ data: Theme.of(context).copyWith(
+ dividerColor: Colors.transparent,
+ ),
+ child: ExpansionTile(
+ title: Text(question.question),
+ iconColor: PharMeTheme.iconColor,
+ collapsedIconColor: PharMeTheme.iconColor,
+ onExpansionChanged: (value) {
+ if (value) _scrollToSelectedContent(key: key);
+ },
+ children: [
+ ListTile(
+ contentPadding: EdgeInsets.only(
+ left: PharMeTheme.mediumSpace,
+ right: PharMeTheme.mediumSpace,
+ bottom: PharMeTheme.smallSpace,
+ ),
+ title: Text(question.answer),
+ ),
+ ],
+ ),
),
- ],
- ),
- );
+ );
}
void _scrollToSelectedContent({required GlobalKey key}) {
@@ -78,6 +101,7 @@ class FaqPage extends StatelessWidget {
Scrollable.ensureVisible(
keyContext,
duration: Duration(milliseconds: 200),
+ alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd,
);
});
}
diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb
index 990f60140..df557a230 100644
--- a/app/lib/l10n/app_en.arb
+++ b/app/lib/l10n/app_en.arb
@@ -23,6 +23,7 @@
"update_warning_title": "Updated guidelines",
"update_warning_body": "The guidelines for gene-drug interactions were updated. Please review your information, especially for medications you are currently taking.",
+
"faq_contact_us": "Do you have unanswered questions or feedback? Contact us",
"general_continue": "Continue",
@@ -150,7 +151,6 @@
}
}
},
- "drugs_page_your_genome": "Your genome",
"drugs_page_guidelines_empty": "No guidelines are present for {drugName}",
"@drugs_page_guidelines_empty": {
"description": "Disclaimer when a drug does not have guidelines",
@@ -161,16 +161,15 @@
}
}
},
- "drugs_page_header_further_info": "Further information",
"drugs_page_header_synonyms": "Other names",
"drugs_page_header_drugclass": "Drug class",
- "drugs_page_header_drug": "Drug",
- "drugs_page_header_druginfo": "Information",
+ "drugs_page_header_drug": "Drug information",
"drugs_page_header_active": "Usage status",
- "drugs_page_active": "I am currently taking this drug.",
+ "drugs_page_active": "I am currently taking this drug",
+ "drugs_page_inactive": "I am not taking this drug",
"drugs_page_active_warn_header": "Are you sure you want to change the drug usage status?",
"drugs_page_active_warn": "This can influence your results for other drugs.",
- "drugs_page_header_guideline": "Clinical Guideline",
+ "drugs_page_header_guideline": "DNA-based clinical guideline",
"drugs_page_no_guidelines_for_phenotype_implication": "More information is needed to comment on your DNA's influence on {drugName}.",
"@drugs_page_no_guidelines_for_phenotype_implication": {
"description": "Disclaimer for when no guidelines was found for the current drug based on the user's phenotype",
@@ -344,7 +343,8 @@
"settings_page_account_settings": "Settings",
"settings_page_delete_data": "Delete app data",
"settings_page_delete_data_text": "Are you sure that you want to delete all app data? This also includes your genetic data and will reset the app.",
- "settings_page_delete_data_confirmation": "I understand that my genetic data will be deleted and it might not be possible to import it again.",
+ "settings_page_delete_data_additional_text": "Your genetic data will be deleted and it might not be possible to import it again.",
+ "settings_page_delete_data_confirmation": "I understand the consequences and want to delete all app data",
"settings_page_more": "More",
"settings_page_onboarding": "Onboarding",
"settings_page_about_us": "About us",
@@ -353,6 +353,7 @@
"settings_page_privacy_policy_text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
"settings_page_terms_and_conditions": "Terms of use",
"settings_page_terms_and_conditions_text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
+ "settings_page_help_and_feedback": "Help & Feedback",
"settings_page_contact_us": "Contact us",
"comprehension_intro_text": "Would you like to participate in a survey aiming to measure user comprehension of content in the app? This would help us make PharMe more understandable for everyone!",
diff --git a/app/lib/login/pages/cubit.dart b/app/lib/login/cubit.dart
similarity index 76%
rename from app/lib/login/pages/cubit.dart
rename to app/lib/login/cubit.dart
index b360f7732..b7f806c8f 100644
--- a/app/lib/login/pages/cubit.dart
+++ b/app/lib/login/cubit.dart
@@ -5,22 +5,22 @@ import 'package:flutter_web_auth/flutter_web_auth.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:http/http.dart' as http;
-import '../../../common/module.dart';
-import '../models/lab.dart';
+import '../../common/module.dart';
+import 'models/lab.dart';
part 'cubit.freezed.dart';
-class LoginPageCubit extends Cubit {
- LoginPageCubit(this.activeDrugs): super(LoginPageState.initial());
+class LoginCubit extends Cubit {
+ LoginCubit(this.activeDrugs): super(LoginState.initial());
ActiveDrugs activeDrugs;
- void revertToInitialState() => emit(LoginPageState.initial());
+ void revertToInitialState() => emit(LoginState.initial());
// signInAndLoadUserData authenticates a user with a Lab and fetches their
// genomic data from it's endpoint.
Future signInAndLoadUserData(BuildContext context, Lab lab) async {
- emit(LoginPageState.loadingUserData());
+ emit(LoginState.loadingUserData());
// authenticate
String? token;
@@ -38,7 +38,7 @@ class LoginPageCubit extends Cubit {
}
if (token == null) {
- emit(LoginPageState.error(
+ emit(LoginState.error(
// ignore: use_build_context_synchronously
context.l10n.err_could_not_retrieve_access_token,
));
@@ -56,10 +56,10 @@ class LoginPageCubit extends Cubit {
// login + fetching of data successful
MetaData.instance.isLoggedIn = true;
await MetaData.save();
- emit(LoginPageState.loadedUserData());
+ emit(LoginState.loadedUserData());
} catch (e) {
// ignore: use_build_context_synchronously
- emit(LoginPageState.error(context.l10n.err_fetch_user_data_failed));
+ emit(LoginState.error(context.l10n.err_fetch_user_data_failed));
}
}
@@ -102,9 +102,9 @@ class LoginPageCubit extends Cubit {
}
@freezed
-class LoginPageState with _$LoginPageState {
- const factory LoginPageState.initial() = _InitialState;
- const factory LoginPageState.loadingUserData() = _LoadingUserDataState;
- const factory LoginPageState.loadedUserData() = _LoadedUserDataState;
- const factory LoginPageState.error(String string) = _ErrorState;
+class LoginState with _$LoginState {
+ const factory LoginState.initial() = _InitialState;
+ const factory LoginState.loadingUserData() = _LoadingUserDataState;
+ const factory LoginState.loadedUserData() = _LoadedUserDataState;
+ const factory LoginState.error(String string) = _ErrorState;
}
diff --git a/app/lib/login/module.dart b/app/lib/login/module.dart
index 5fbae01e8..ad844be59 100644
--- a/app/lib/login/module.dart
+++ b/app/lib/login/module.dart
@@ -1,12 +1,7 @@
import '../common/module.dart';
-import 'pages/login.dart';
-// We need to expose all pages for AutoRouter
-export 'pages/cubit.dart';
+// For generated route
+export 'cubit.dart';
export 'pages/login.dart';
-const loginRoutes = AutoRoute(
- path: 'login',
- name: 'LoginRouter',
- page: LoginPage,
-);
+AutoRoute loginRoute() => AutoRoute(path: '/login', page: LoginRoute.page);
\ No newline at end of file
diff --git a/app/lib/login/pages/login.dart b/app/lib/login/pages/login.dart
index 90f5f5deb..30b8ba6d6 100644
--- a/app/lib/login/pages/login.dart
+++ b/app/lib/login/pages/login.dart
@@ -3,16 +3,17 @@ import 'package:provider/provider.dart';
import '../../../common/module.dart';
import '../../common/widgets/full_width_button.dart';
+import '../cubit.dart';
import '../models/lab.dart';
-import 'cubit.dart';
+@RoutePage()
class LoginPage extends HookWidget {
const LoginPage({
- Key? key,
+ super.key,
@visibleForTesting this.cubit,
- }) : super(key: key);
+ });
- final LoginPageCubit? cubit;
+ final LoginCubit? cubit;
@override
Widget build(BuildContext context) {
@@ -20,8 +21,8 @@ class LoginPage extends HookWidget {
return Consumer(
builder: (context, activeDrugs, child) => BlocProvider(
- create: (context) => cubit ?? LoginPageCubit(activeDrugs),
- child: BlocBuilder(
+ create: (context) => cubit ?? LoginCubit(activeDrugs),
+ child: BlocBuilder(
builder: (context, state) {
return unscrollablePageScaffold(
padding: PharMeTheme.largeSpace,
@@ -66,7 +67,7 @@ class LoginPage extends HookWidget {
(el) => el.name == dropdownValue.value,
);
await context
- .read()
+ .read()
.signInAndLoadUserData(context, selectedLab);
}
@@ -87,7 +88,12 @@ class LoginPage extends HookWidget {
DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
- dropdownOverButton: true,
+ dropdownStyleData: DropdownStyleData(
+ isOverButton: true,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(16),
+ ),
+ ),
hint: Text(context.l10n.auth_choose_lab),
value: dropdownValue.value,
onChanged: (value) {
@@ -99,13 +105,12 @@ class LoginPage extends HookWidget {
child: Text(lab.name),
))
.toList(),
- buttonPadding: const EdgeInsets.only(left: 16, right: 16),
- buttonDecoration: BoxDecoration(
- borderRadius: BorderRadius.circular(32),
- border: Border.all(color: PharMeTheme.borderColor),
- ),
- dropdownDecoration: BoxDecoration(
- borderRadius: BorderRadius.circular(16),
+ buttonStyleData: ButtonStyleData(
+ padding: const EdgeInsets.only(left: 16, right: 16),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(32),
+ border: Border.all(color: PharMeTheme.borderColor),
+ ),
),
),
),
@@ -117,7 +122,7 @@ class LoginPage extends HookWidget {
return _buildColumnWrapper(
action: () => overwriteRoutes(
context,
- nextPage: OnboardingRouter(),
+ nextPage: OnboardingRoute(),
),
actionText: context.l10n.general_continue,
children: [
@@ -138,7 +143,7 @@ class LoginPage extends HookWidget {
Widget _buildErrorScreen(BuildContext context, String message) {
return _buildColumnWrapper(
- action: () => context.read().revertToInitialState(),
+ action: () => context.read().revertToInitialState(),
actionText: context.l10n.general_retry,
children: [
Icon(
diff --git a/app/lib/main.dart b/app/lib/main.dart
index 9a4ad8695..bfb574653 100644
--- a/app/lib/main.dart
+++ b/app/lib/main.dart
@@ -1,5 +1,6 @@
import 'package:provider/provider.dart';
+import 'app.dart';
import 'common/module.dart';
Future main() async {
diff --git a/app/lib/main/module.dart b/app/lib/main/module.dart
new file mode 100644
index 000000000..d3d6986ac
--- /dev/null
+++ b/app/lib/main/module.dart
@@ -0,0 +1,10 @@
+import '../common/module.dart';
+
+// For generated route
+export 'pages/main.dart';
+
+AutoRoute mainRoute({ required List children }) => AutoRoute(
+ path: '/main',
+ page: MainRoute.page,
+ children: children,
+);
\ No newline at end of file
diff --git a/app/lib/common/pages/main/main.dart b/app/lib/main/pages/main.dart
similarity index 83%
rename from app/lib/common/pages/main/main.dart
rename to app/lib/main/pages/main.dart
index 904a16851..98db08039 100644
--- a/app/lib/common/pages/main/main.dart
+++ b/app/lib/main/pages/main.dart
@@ -1,8 +1,4 @@
-import 'package:auto_route/auto_route.dart';
-import 'package:flutter/material.dart';
-
-import '../../l10n.dart';
-import '../../routing/router.dart';
+import '../../common/module.dart';
class TabRouteDefinition {
TabRouteDefinition({
@@ -18,30 +14,31 @@ class TabRouteDefinition {
List getTabRoutesDefinition(BuildContext context) {
return [
TabRouteDefinition(
- pageRouteInfo: ReportRouter(),
+ pageRouteInfo: ReportRoute(),
label: context.l10n.nav_report,
icon: Icon(Icons.summarize_rounded),
),
TabRouteDefinition(
- pageRouteInfo: SearchRouter(),
+ pageRouteInfo: SearchRoute(),
label: context.l10n.nav_drugs,
icon: Icon(Icons.medication_rounded),
),
TabRouteDefinition(
- pageRouteInfo: FaqRouter(),
+ pageRouteInfo: FaqRoute(),
label: context.l10n.nav_faq,
icon: Icon(Icons.lightbulb_rounded),
),
TabRouteDefinition(
- pageRouteInfo: SettingsRouter(),
+ pageRouteInfo: MoreRoute(),
label: context.l10n.nav_more,
icon: Icon(Icons.more_horiz_rounded),
),
];
}
+@RoutePage()
class MainPage extends StatelessWidget {
- const MainPage({Key? key}) : super(key: key);
+ const MainPage({super.key});
@override
Widget build(BuildContext context) {
diff --git a/app/lib/more/module.dart b/app/lib/more/module.dart
new file mode 100644
index 000000000..a18bcc3de
--- /dev/null
+++ b/app/lib/more/module.dart
@@ -0,0 +1,23 @@
+import '../common/module.dart';
+
+// For generated routes
+export 'pages/about.dart';
+export 'pages/more.dart';
+export 'pages/privacy.dart';
+export 'pages/terms.dart';
+
+@RoutePage()
+class MoreRootPage extends AutoRouter {}
+
+AutoRoute aboutRoute() => AutoRoute(path: 'about', page: AboutRoute.page);
+AutoRoute privacyRoute() => AutoRoute(path: 'privacy', page: PrivacyRoute.page);
+AutoRoute termsRoute() => AutoRoute(path: 'terms', page: TermsRoute.page);
+
+AutoRoute moreRoute({ required List children }) => AutoRoute(
+ path: 'more',
+ page: MoreRootRoute.page,
+ children: [
+ AutoRoute(path: '', page: MoreRoute.page),
+ ...children,
+ ],
+);
\ No newline at end of file
diff --git a/app/lib/settings/pages/about_us.dart b/app/lib/more/pages/about.dart
similarity index 82%
rename from app/lib/settings/pages/about_us.dart
rename to app/lib/more/pages/about.dart
index e5030e59d..852bac33d 100644
--- a/app/lib/settings/pages/about_us.dart
+++ b/app/lib/more/pages/about.dart
@@ -1,7 +1,8 @@
import '../../common/module.dart';
-class AboutUsPage extends StatelessWidget {
- const AboutUsPage({Key? key}) : super(key: key);
+@RoutePage()
+class AboutPage extends StatelessWidget {
+ const AboutPage({super.key});
@override
Widget build(BuildContext context) {
diff --git a/app/lib/more/pages/more.dart b/app/lib/more/pages/more.dart
new file mode 100644
index 000000000..b5962d1fc
--- /dev/null
+++ b/app/lib/more/pages/more.dart
@@ -0,0 +1,130 @@
+import '../../common/module.dart';
+import '../utils.dart';
+
+@RoutePage()
+class MorePage extends StatelessWidget {
+ const MorePage({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return PopScope(
+ canPop: false,
+ child: pageScaffold(title: context.l10n.tab_more, body: [
+ SubheaderDivider(
+ text: context.l10n.settings_page_account_settings,
+ useLine: false,
+ ),
+ _buildSettingsItem(
+ title: context.l10n.drug_selection_header,
+ onTap: () => context.router.push(
+ DrugSelectionRoute(concludesOnboarding: false)
+ ),
+ ),
+ _buildSettingsItem(
+ title: context.l10n.settings_page_delete_data,
+ onTap: () => showDialog(
+ context: context,
+ builder: (_) => DeleteDataDialog(),
+ ),
+ ),
+ SubheaderDivider(
+ text: context.l10n.settings_page_more,
+ useLine: false,
+ ),
+ _buildSettingsItem(
+ title: context.l10n.settings_page_onboarding,
+ onTap: () => context.router.push(OnboardingRoute(isRevisiting: true)),
+ ),
+ _buildSettingsItem(
+ title: context.l10n.settings_page_about_us,
+ onTap: () => context.router.push(AboutRoute()),
+ ),
+ _buildSettingsItem(
+ title: context.l10n.settings_page_privacy_policy,
+ onTap: () => context.router.push(PrivacyRoute()),
+ ),
+ _buildSettingsItem(
+ title: context.l10n.settings_page_terms_and_conditions,
+ onTap: () => context.router.push(TermsRoute()),
+ ),
+ SubheaderDivider(
+ text: context.l10n.settings_page_help_and_feedback,
+ useLine: false,
+ ),
+ _buildSettingsItem(
+ title: context.l10n.settings_page_contact_us,
+ onTap: sendEmail)
+ ]),
+ );
+ }
+
+ Widget _buildSettingsItem({
+ required String title,
+ required void Function() onTap,
+ }) => ListTile(
+ title: Text(title),
+ trailing: Icon(Icons.chevron_right_rounded),
+ iconColor: PharMeTheme.iconColor,
+ onTap: onTap,
+ );
+}
+
+class DeleteDataDialog extends HookWidget {
+ @override
+ Widget build(BuildContext context) {
+ final agreedToDeletion = useState(false);
+
+ return DialogWrapper(
+ title: context.l10n.settings_page_delete_data,
+ content: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ DialogContentText(context.l10n.settings_page_delete_data_text),
+ SizedBox(height: PharMeTheme.mediumSpace),
+ DialogContentText(
+ context.l10n.settings_page_delete_data_additional_text,
+ ),
+ SizedBox(height: PharMeTheme.mediumSpace),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox(
+ width: PharMeTheme.mediumToLargeSpace,
+ height: PharMeTheme.mediumToLargeSpace,
+ child: CheckboxWrapper(
+ isChecked: agreedToDeletion.value,
+ onChanged: (value) =>
+ agreedToDeletion.value = value ?? agreedToDeletion.value,
+ ),
+ ),
+ SizedBox(width: PharMeTheme.smallSpace),
+ Expanded(
+ child: DialogContentText(
+ context.l10n.settings_page_delete_data_confirmation,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ actions: [
+ DialogAction(
+ onPressed: context.router.root.pop,
+ text: context.l10n.action_cancel,
+ ),
+ DialogAction(
+ onPressed: agreedToDeletion.value
+ ? () async {
+ await deleteAllAppData();
+ // ignore: use_build_context_synchronously
+ await overwriteRoutes(context, nextPage: LoginRoute());
+ }
+ : null,
+ text: context.l10n.action_continue,
+ isDestructive: true,
+ ),
+ ],
+ );
+ }
+}
diff --git a/app/lib/settings/pages/privacy_policy.dart b/app/lib/more/pages/privacy.dart
similarity index 80%
rename from app/lib/settings/pages/privacy_policy.dart
rename to app/lib/more/pages/privacy.dart
index 82ff95f57..f5125ec85 100644
--- a/app/lib/settings/pages/privacy_policy.dart
+++ b/app/lib/more/pages/privacy.dart
@@ -1,7 +1,8 @@
import '../../common/module.dart';
-class PrivacyPolicyPage extends StatelessWidget {
- const PrivacyPolicyPage({Key? key}) : super(key: key);
+@RoutePage()
+class PrivacyPage extends StatelessWidget {
+ const PrivacyPage({super.key});
@override
Widget build(BuildContext context) {
diff --git a/app/lib/settings/pages/terms_and_conditions.dart b/app/lib/more/pages/terms.dart
similarity index 82%
rename from app/lib/settings/pages/terms_and_conditions.dart
rename to app/lib/more/pages/terms.dart
index 9c1f29d0d..8844f17ea 100644
--- a/app/lib/settings/pages/terms_and_conditions.dart
+++ b/app/lib/more/pages/terms.dart
@@ -1,7 +1,8 @@
import '../../common/module.dart';
-class TermsAndConditionsPage extends StatelessWidget {
- const TermsAndConditionsPage({Key? key}) : super(key: key);
+@RoutePage()
+class TermsPage extends StatelessWidget {
+ const TermsPage({super.key});
@override
Widget build(BuildContext context) {
diff --git a/app/lib/settings/utils.dart b/app/lib/more/utils.dart
similarity index 92%
rename from app/lib/settings/utils.dart
rename to app/lib/more/utils.dart
index 8a7efae23..e049ba8f6 100644
--- a/app/lib/settings/utils.dart
+++ b/app/lib/more/utils.dart
@@ -1,6 +1,5 @@
import 'package:path_provider/path_provider.dart';
-import '../common/models/drug/cached_drugs.dart';
import '../common/module.dart';
Future deleteAllAppData() async {
diff --git a/app/lib/onboarding/module.dart b/app/lib/onboarding/module.dart
index e01f2332a..1b99465f7 100644
--- a/app/lib/onboarding/module.dart
+++ b/app/lib/onboarding/module.dart
@@ -1,10 +1,9 @@
import '../common/module.dart';
-import 'pages/onboarding.dart';
+// For generated route
export 'pages/onboarding.dart';
-const onboardingRoutes = AutoRoute(
- path: 'onboarding',
- name: 'OnboardingRouter',
- page: OnboardingPage,
-);
+AutoRoute onboardingRoute() => AutoRoute(
+ path: '/onboarding',
+ page: OnboardingRoute.page,
+);
\ No newline at end of file
diff --git a/app/lib/onboarding/pages/onboarding.dart b/app/lib/onboarding/pages/onboarding.dart
index 158cdffa4..5763ae8ff 100644
--- a/app/lib/onboarding/pages/onboarding.dart
+++ b/app/lib/onboarding/pages/onboarding.dart
@@ -1,6 +1,7 @@
import '../../../common/module.dart' hide MetaData;
import '../../common/models/metadata.dart';
+@RoutePage()
class OnboardingPage extends HookWidget {
OnboardingPage({ this.isRevisiting = false });
@@ -95,7 +96,7 @@ class OnboardingPage extends HookWidget {
right: PharMeTheme.mediumToLargeSpace,
child: IconButton(
icon: Icon(Icons.close, size: 32, color: Colors.white,),
- onPressed: () => context.navigateBack(),
+ onPressed: () => context.router.back(),
)
),
Positioned(
@@ -167,13 +168,13 @@ class OnboardingPage extends HookWidget {
onPressed: () async {
if (isLastPage) {
if (isRevisiting) {
- context.router.navigateBack();
+ context.router.back();
} else {
MetaData.instance.onboardingDone = true;
await MetaData.save();
// ignore: use_build_context_synchronously
await context.router.push(
- DrugSelectionRouter(concludesOnboarding: true)
+ DrugSelectionRoute(concludesOnboarding: true)
);
}
} else {
diff --git a/app/lib/report/module.dart b/app/lib/report/module.dart
index 25a69296c..a2fc0a7bb 100644
--- a/app/lib/report/module.dart
+++ b/app/lib/report/module.dart
@@ -1,18 +1,19 @@
import '../common/module.dart';
-import '../search/module.dart';
-import 'pages/gene.dart';
-import 'pages/report.dart';
+// For generated routes
export 'pages/gene.dart';
export 'pages/report.dart';
-const reportRoutes = AutoRoute(
+@RoutePage()
+class ReportRootPage extends AutoRouter {}
+
+AutoRoute geneRoute() => AutoRoute(page: GeneRoute.page);
+
+AutoRoute reportRoute({ required List children }) => AutoRoute(
path: 'report',
- name: 'ReportRouter',
- page: EmptyRouterPage,
+ page: ReportRootRoute.page,
children: [
- AutoRoute(path: '', page: ReportPage),
- AutoRoute(page: GenePage),
- AutoRoute(page: DrugPage)
+ AutoRoute(path: '', page: ReportRoute.page),
+ ...children,
],
);
diff --git a/app/lib/report/pages/gene.dart b/app/lib/report/pages/gene.dart
index fae05a03d..f42159fb1 100644
--- a/app/lib/report/pages/gene.dart
+++ b/app/lib/report/pages/gene.dart
@@ -1,9 +1,9 @@
import 'package:provider/provider.dart';
import '../../common/module.dart';
-import '../../common/pages/drug/widgets/sub_header.dart';
-import '../../common/pages/drug/widgets/tooltip_icon.dart';
+import '../../drug/widgets/module.dart';
+@RoutePage()
class GenePage extends HookWidget {
GenePage(this.phenotype)
: cubit = DrugListCubit(
@@ -37,6 +37,7 @@ class GenePage extends HookWidget {
),
SizedBox(height: PharMeTheme.smallToMediumSpace),
RoundedCard(
+ radius: PharMeTheme.mediumSpace,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
diff --git a/app/lib/report/pages/report.dart b/app/lib/report/pages/report.dart
index 84524a03a..9579f8e26 100644
--- a/app/lib/report/pages/report.dart
+++ b/app/lib/report/pages/report.dart
@@ -1,9 +1,8 @@
import 'package:provider/provider.dart';
-import '../../common/models/drug/cached_drugs.dart';
import '../../common/module.dart';
-import '../../common/utilities/color_utils.dart';
+@RoutePage()
class ReportPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
@@ -25,45 +24,37 @@ class ReportPage extends StatelessWidget {
lookupkey: notTestedString
)
);
- return WillPopScope(
+ return PopScope(
+ canPop: false,
child: unscrollablePageScaffold(
title: context.l10n.tab_report,
barBottom: context.l10n.report_content_explanation,
body: Column(
children: [
+ if (hasActiveInhibitors) Padding(
+ padding: EdgeInsets.only(top: PharMeTheme.smallSpace),
+ child: PageIndicatorExplanation(
+ context.l10n.report_page_indicator_explanation(
+ drugInteractionIndicatorName,
+ drugInteractionIndicator
+ ),
+ ),
+ ),
scrollList(
- userPhenotypes.map((phenotype) =>
- Column(
- key: Key('gene-card-${phenotype.geneSymbol}'),
- children: [
- GeneCard(phenotype),
- SizedBox(height: 8)
- ]
- )
- ).toList()),
- if (hasActiveInhibitors) drugInteractionExplanation(context),
+ userPhenotypes.map((phenotype) => GeneCard(
+ phenotype,
+ key: Key('gene-card-${phenotype.geneSymbol}')
+ )).toList(),
+ ),
]
)
),
- onWillPop: () async => false,
);
}
-
- Widget drugInteractionExplanation(BuildContext context) {
- return Column(children: [
- SizedBox(height: PharMeTheme.smallSpace),
- Text(
- context.l10n.report_page_indicator_explanation(
- drugInteractionIndicatorName,
- drugInteractionIndicator
- )
- ),
- ]);
- }
}
class GeneCard extends StatelessWidget {
- const GeneCard(this.phenotype);
+ const GeneCard(this.phenotype, { super.key });
final CpicPhenotype phenotype;
@@ -107,7 +98,6 @@ class GeneCard extends StatelessWidget {
).toList();
return RoundedCard(
onTap: () => context.router.push(GeneRoute(phenotype: phenotype)),
- padding: EdgeInsets.all(8),
radius: 16,
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Expanded(
diff --git a/app/lib/search/module.dart b/app/lib/search/module.dart
index 09f1e070c..c98075765 100644
--- a/app/lib/search/module.dart
+++ b/app/lib/search/module.dart
@@ -1,19 +1,16 @@
-import 'package:auto_route/auto_route.dart';
+import '../common/module.dart';
-import '../common/pages/drug/drug.dart';
-import 'pages/search.dart';
-
-export '../common/models/module.dart';
-export '../common/pages/drug/cubit.dart';
-export '../common/pages/drug/drug.dart';
+// For generated routes
export 'pages/search.dart';
-const searchRoutes = AutoRoute(
+@RoutePage()
+class SearchRootPage extends AutoRouter {}
+
+AutoRoute searchRoute({ required List children }) => AutoRoute(
path: 'search',
- name: 'SearchRouter',
- page: EmptyRouterPage,
+ page: SearchRootRoute.page,
children: [
- AutoRoute(path: '', page: SearchPage),
- AutoRoute(page: DrugPage),
+ AutoRoute(path: '', page: SearchRoute.page),
+ ...children,
],
-);
+);
\ No newline at end of file
diff --git a/app/lib/search/pages/search.dart b/app/lib/search/pages/search.dart
index e7aeb1c97..7ba0bed0a 100644
--- a/app/lib/search/pages/search.dart
+++ b/app/lib/search/pages/search.dart
@@ -2,12 +2,12 @@ import '../../../common/module.dart';
import '../../common/widgets/drug_list/drug_items/drug_cards.dart';
import '../../common/widgets/drug_search.dart';
+@RoutePage()
class SearchPage extends HookWidget {
SearchPage({
- Key? key,
+ super.key,
@visibleForTesting DrugListCubit? cubit,
- }) : cubit = cubit ?? DrugListCubit(),
- super(key: key);
+ }) : cubit = cubit ?? DrugListCubit();
final DrugListCubit cubit;
@@ -18,7 +18,8 @@ class SearchPage extends HookWidget {
await cubit.loadDrugs(useCache: false);
}
});
- return WillPopScope(
+ return PopScope(
+ canPop: false,
child: unscrollablePageScaffold(
title: context.l10n.tab_drugs,
body: DrugSearch(
@@ -28,7 +29,6 @@ class SearchPage extends HookWidget {
showDrugInteractionIndicator: true,
),
),
- onWillPop: () async => false,
);
}
}
diff --git a/app/lib/settings/module.dart b/app/lib/settings/module.dart
deleted file mode 100644
index 8fad25f3b..000000000
--- a/app/lib/settings/module.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-import 'package:auto_route/auto_route.dart';
-
-import '../common/module.dart';
-
-import 'pages/about_us.dart';
-import 'pages/privacy_policy.dart';
-import 'pages/settings.dart';
-import 'pages/terms_and_conditions.dart';
-
-// We need to expose all pages for AutoRouter
-export 'pages/about_us.dart';
-export 'pages/privacy_policy.dart';
-export 'pages/settings.dart';
-export 'pages/terms_and_conditions.dart';
-
-const settingsRoutes = AutoRoute(
- path: 'settings',
- name: 'SettingsRouter',
- page: EmptyRouterPage,
- children: [
- AutoRoute(path: '', page: SettingsPage),
- AutoRoute(path: 'about_us', page: AboutUsPage),
- AutoRoute(path: 'privacy_policy', page: PrivacyPolicyPage),
- AutoRoute(path: 'terms_and_conditions', page: TermsAndConditionsPage),
- ],
-);
diff --git a/app/lib/settings/pages/settings.dart b/app/lib/settings/pages/settings.dart
deleted file mode 100644
index 3c522d87a..000000000
--- a/app/lib/settings/pages/settings.dart
+++ /dev/null
@@ -1,114 +0,0 @@
-import '../../common/module.dart';
-import '../../common/pages/drug/widgets/adaptive_dialog.dart';
-import '../utils.dart';
-
-class SettingsPage extends StatelessWidget {
- const SettingsPage({Key? key}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return WillPopScope(
- child: pageScaffold(title: context.l10n.tab_more, body: [
- ListTile(
- title: Text(
- context.l10n.settings_page_account_settings,
- style: PharMeTheme.textTheme.bodyMedium,
- ),
- dense: true,
- ),
- ListTile(
- title: Text(context.l10n.drug_selection_header),
- trailing: Icon(Icons.chevron_right_rounded),
- onTap: () => context.router.push(
- DrugSelectionRouter(concludesOnboarding: false)
- ),
- ),
- ListTile(
- title: Text(context.l10n.settings_page_delete_data),
- trailing: Icon(Icons.chevron_right_rounded),
- onTap: () => showDialog(
- context: context,
- builder: (_) => DeleteDataDialog(),
- ),
- ),
- Divider(),
- ListTile(
- title: Text(
- context.l10n.settings_page_more,
- style: PharMeTheme.textTheme.bodyMedium,
- ),
- dense: true,
- ),
- ListTile(
- title: Text(context.l10n.settings_page_onboarding),
- trailing: Icon(Icons.chevron_right_rounded),
- onTap: () => context.router.push(OnboardingRouter(isRevisiting: true)),
- ),
- ListTile(
- title: Text(context.l10n.settings_page_about_us),
- trailing: Icon(Icons.chevron_right_rounded),
- onTap: () => context.router.push(AboutUsRoute()),
- ),
- ListTile(
- title: Text(context.l10n.settings_page_privacy_policy),
- trailing: Icon(Icons.chevron_right_rounded),
- onTap: () => context.router.push(PrivacyPolicyRoute()),
- ),
- ListTile(
- title: Text(context.l10n.settings_page_terms_and_conditions),
- trailing: Icon(Icons.chevron_right_rounded),
- onTap: () => context.router.push(TermsAndConditionsRoute()),
- ),
- Divider(),
- ListTile(
- title: Text(context.l10n.settings_page_contact_us),
- trailing: Icon(Icons.chevron_right_rounded),
- onTap: sendEmail)
- ]),
- onWillPop: () async => false,
- );
- }
-}
-
-class DeleteDataDialog extends HookWidget {
- @override
- Widget build(BuildContext context) {
- final agreedToDeletion = useState(false);
-
- return AdaptiveAlertDialog(
- title: context.l10n.settings_page_delete_data,
- content: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text(context.l10n.settings_page_delete_data_text),
- SizedBox(height: PharMeTheme.mediumSpace),
- CheckboxListTile(
- value: agreedToDeletion.value,
- onChanged: (value) => agreedToDeletion.value = value
- ?? agreedToDeletion.value,
- title: Text(context.l10n.settings_page_delete_data_confirmation),
- controlAffinity: ListTileControlAffinity.leading,
- contentPadding: EdgeInsets.zero,
- activeColor: PharMeTheme.primaryColor,
- ),
- ]),
- actions: [
- AdaptiveDialogAction(
- onPressed: context.router.root.pop,
- text: context.l10n.action_cancel,
- ),
- AdaptiveDialogAction(
- isDestructive: true,
- onPressed: agreedToDeletion.value
- ? () async {
- await deleteAllAppData();
- // ignore: use_build_context_synchronously
- await overwriteRoutes(context, nextPage: LoginRouter());
- }
- : null,
- text: context.l10n.action_continue,
- ),
- ],
- );
- }
-}
diff --git a/app/pubspec.lock b/app/pubspec.lock
index 7638491e3..40cf68ec4 100644
--- a/app/pubspec.lock
+++ b/app/pubspec.lock
@@ -5,58 +5,58 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
- sha256: d37dfd404e9bb23adb23ee61fad5b8e14e0ae018fb6948eda6ca44b197ff1158
+ sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051
url: "https://pub.dev"
source: hosted
- version: "43.0.0"
+ version: "64.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
- sha256: "40cbac251e4fffed9c85afca62e1d8236f4778d647934220f38007e2bd9009d8"
+ sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893"
url: "https://pub.dev"
source: hosted
- version: "4.3.1"
+ version: "6.2.0"
archive:
dependency: transitive
description:
name: archive
- sha256: "80e5141fafcb3361653ce308776cfd7d45e6e9fbb429e14eec571382c0c5fecb"
+ sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
url: "https://pub.dev"
source: hosted
- version: "3.3.2"
+ version: "3.4.9"
args:
dependency: transitive
description:
name: args
- sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515
+ sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
url: "https://pub.dev"
source: hosted
- version: "2.3.1"
+ version: "2.4.2"
async:
dependency: transitive
description:
name: async
- sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
+ sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
- version: "2.10.0"
+ version: "2.11.0"
auto_route:
dependency: "direct main"
description:
name: auto_route
- sha256: "931f7c93fdfff8a0344b885dd2f3001746c01fb05820208fe51ddccc6f081a13"
+ sha256: "82f8df1d177416bc6b7a449127d0270ff1f0f633a91f2ceb7a85d4f07c3affa1"
url: "https://pub.dev"
source: hosted
- version: "4.2.1"
+ version: "7.8.4"
auto_route_generator:
dependency: "direct dev"
description:
name: auto_route_generator
- sha256: "3d0239a0d6f4a0a5b9f511b4a46f43812a6f2261887de8f5a0bdfe2a44465073"
+ sha256: "11067a3bcd643812518fe26c0c9ec073990286cabfd9d74b6da9ef9b913c4d22"
url: "https://pub.dev"
source: hosted
- version: "4.2.1"
+ version: "7.3.2"
auto_size_text:
dependency: "direct main"
description:
@@ -69,34 +69,42 @@ packages:
dependency: transitive
description:
name: barcode
- sha256: "52570564684bbb0240a9f1fdb6bad12adc5e0540103c1c96d6dd550bd928b1c9"
+ sha256: "2a8b2ee065f419c2aeda141436cc556d91ae772d220fd80679f4d431d6c2ab43"
url: "https://pub.dev"
source: hosted
- version: "2.2.3"
+ version: "2.2.5"
+ bidi:
+ dependency: transitive
+ description:
+ name: bidi
+ sha256: "1a7d0c696324b2089f72e7671fd1f1f64fef44c980f3cebc84e803967c597b63"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.10"
black_hole_flutter:
dependency: "direct main"
description:
name: black_hole_flutter
- sha256: ad957dd07106932f07b040dcc4d08c7532a284821183a21ca5ad993b545c2707
+ sha256: d1646e3638c15cd56a0f075128fa50317d26e7c824bde6b981d70118be34bd2f
url: "https://pub.dev"
source: hosted
- version: "0.3.5"
+ version: "1.1.0"
bloc:
dependency: "direct main"
description:
name: bloc
- sha256: bd4f8027bfa60d96c8046dec5ce74c463b2c918dce1b0d36593575995344534a
+ sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49"
url: "https://pub.dev"
source: hosted
- version: "8.1.0"
+ version: "8.1.2"
bloc_test:
dependency: "direct dev"
description:
name: bloc_test
- sha256: "622b97678bf8c06a94f4c26a89ee9ebf7319bf775383dee2233e86e1f94ee28d"
+ sha256: "02f04270be5abae8df171143e61a0058a7acbce5dcac887612e89bb40cca4c33"
url: "https://pub.dev"
source: hosted
- version: "9.1.0"
+ version: "9.1.5"
boolean_selector:
dependency: transitive
description:
@@ -109,50 +117,50 @@ packages:
dependency: transitive
description:
name: build
- sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777"
+ sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
url: "https://pub.dev"
source: hosted
- version: "2.3.1"
+ version: "2.4.1"
build_config:
dependency: transitive
description:
name: build_config
- sha256: "5b7355c14258f5e7df24bad1566f7b991de3e54aeacfb94e1a65e5233d9739c1"
+ sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
url: "https://pub.dev"
source: hosted
- version: "1.1.0"
+ version: "1.1.1"
build_daemon:
dependency: transitive
description:
name: build_daemon
- sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf"
+ sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1"
url: "https://pub.dev"
source: hosted
- version: "3.1.0"
+ version: "4.0.1"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
- sha256: "9aae031a54ab0beebc30a888c93e900d15ae2fd8883d031dbfbd5ebdb57f5a4c"
+ sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
url: "https://pub.dev"
source: hosted
- version: "2.0.9"
+ version: "2.4.2"
build_runner:
dependency: "direct dev"
description:
name: build_runner
- sha256: "56942f8114731d1e79942cd981cfef29501937ff1bccf4dbdce0273f31f13640"
+ sha256: "67d591d602906ef9201caf93452495ad1812bea2074f04e25dbd7c133785821b"
url: "https://pub.dev"
source: hosted
- version: "2.2.0"
+ version: "2.4.7"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
- sha256: "409c20ff6b6a9c9f4152fc9fcbf16440fedf02fcacc0fb26ea3b8eab9a860a40"
+ sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185
url: "https://pub.dev"
source: hosted
- version: "7.2.4"
+ version: "7.2.11"
built_collection:
dependency: transitive
description:
@@ -165,34 +173,34 @@ packages:
dependency: transitive
description:
name: built_value
- sha256: d7a9cd57c215bdf8d502772447aa6b52a8ab3f956d25d5fdea6ef1df2d2dad60
+ sha256: c9aabae0718ec394e5bc3c7272e6bb0dc0b32201a08fe185ec1d8401d3e39309
url: "https://pub.dev"
source: hosted
- version: "8.4.1"
+ version: "8.8.1"
characters:
dependency: transitive
description:
name: characters
- sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
+ sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
- version: "1.2.1"
- charcode:
+ version: "1.3.0"
+ checked_yaml:
dependency: transitive
description:
- name: charcode
- sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306
+ name: checked_yaml
+ sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.dev"
source: hosted
- version: "1.3.1"
- checked_yaml:
+ version: "2.0.3"
+ cli_util:
dependency: transitive
description:
- name: checked_yaml
- sha256: dd007e4fb8270916820a0d66e24f619266b60773cddd082c6439341645af2659
+ name: cli_util
+ sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
url: "https://pub.dev"
source: hosted
- version: "2.0.1"
+ version: "0.4.1"
clock:
dependency: transitive
description:
@@ -205,74 +213,66 @@ packages:
dependency: transitive
description:
name: code_builder
- sha256: "02ce3596b459c666530f045ad6f96209474e8fee6e4855940a3cee65fb872ec5"
+ sha256: feee43a5c05e7b3199bb375a86430b8ada1b04104f2923d0e03cc01ca87b6d84
url: "https://pub.dev"
source: hosted
- version: "4.3.0"
+ version: "4.9.0"
collection:
dependency: "direct main"
description:
name: collection
- sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
+ sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
- version: "1.17.0"
+ version: "1.18.0"
convert:
dependency: transitive
description:
name: convert
- sha256: "196284f26f69444b7f5c50692b55ec25da86d9e500451dc09333bf2e3ad69259"
+ sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
- version: "3.0.2"
+ version: "3.1.1"
coverage:
dependency: transitive
description:
name: coverage
- sha256: "525ac94733f9ce82507a050bfd62ad89eb1dcbc56308e1e2e17ab11abeee4a75"
+ sha256: "595a29b55ce82d53398e1bcc2cba525d7bd7c59faeb2d2540e9d42c390cfeeeb"
url: "https://pub.dev"
source: hosted
- version: "1.5.0"
+ version: "1.6.4"
crypto:
dependency: transitive
description:
name: crypto
- sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- csslib:
- dependency: transitive
- description:
- name: csslib
- sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745
+ sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
- version: "0.17.2"
+ version: "3.0.3"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
- sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
+ sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
url: "https://pub.dev"
source: hosted
- version: "1.0.5"
+ version: "1.0.6"
dart_style:
dependency: transitive
description:
name: dart_style
- sha256: "8aff82f9b26fd868992e5430335a9d773bfef01e1d852d7ba71bf4c5d9349351"
+ sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368"
url: "https://pub.dev"
source: hosted
- version: "2.2.3"
+ version: "2.3.4"
dartx:
dependency: "direct main"
description:
name: dartx
- sha256: "45d7176701f16c5a5e00a4798791c1964bc231491b879369c818dd9a9c764871"
+ sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244"
url: "https://pub.dev"
source: hosted
- version: "1.1.0"
+ version: "1.2.0"
data_size:
dependency: transitive
description:
@@ -285,58 +285,26 @@ packages:
dependency: "direct main"
description:
name: debug_overlay
- sha256: "33fd675a18cef743454fc15a4f84c3d9e3a6ca3be1b06466746f28b6d791f9fc"
+ sha256: "3c630f1c4e59dca72e9da9caac8602645c252b78fd9f6802ef5b2b260e40a6b2"
url: "https://pub.dev"
source: hosted
- version: "0.1.5"
+ version: "0.2.11"
device_info_plus:
dependency: transitive
description:
name: device_info_plus
- sha256: c2386729379f04cd39ee0d5d4c48d8c8a0e70f7622dac626cbf5e396392602fd
+ sha256: "0042cb3b2a76413ea5f8a2b40cec2a33e01d0c937e91f0f7c211fde4f7739ba6"
url: "https://pub.dev"
source: hosted
- version: "3.2.4"
- device_info_plus_linux:
- dependency: transitive
- description:
- name: device_info_plus_linux
- sha256: e4eb5db4704f5534e872148a21cfcd39581022b63df556da6720d88f7c9f91a9
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- device_info_plus_macos:
- dependency: transitive
- description:
- name: device_info_plus_macos
- sha256: "38871fd2ad31871399d8307630c9f4eb5941dd2c643ee221c44d58de95d367a1"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.3"
+ version: "9.1.1"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
- sha256: b2743934f0efc3e291880d76fb341ea114b7e8417d77ee0f93bd21f5dfd3e8d2
+ sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64
url: "https://pub.dev"
source: hosted
- version: "2.6.1"
- device_info_plus_web:
- dependency: transitive
- description:
- name: device_info_plus_web
- sha256: "38715ad1ef3bee8915dd7bee08a9ac9ab54472a8df425c887062a3046209f663"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.0"
- device_info_plus_windows:
- dependency: transitive
- description:
- name: device_info_plus_windows
- sha256: "8fb1403fc94636d6ab48aeebb5f9379f2ca51cde3b337167ec6f39db09234492"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
+ version: "7.0.0"
diff_match_patch:
dependency: transitive
description:
@@ -349,10 +317,10 @@ packages:
dependency: "direct main"
description:
name: dropdown_button2
- sha256: b036a3006b6cdc964488f4eae366ee83b3b33eaa2677f0292538a82fa85201e1
+ sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1
url: "https://pub.dev"
source: hosted
- version: "1.8.5"
+ version: "2.3.9"
fake_async:
dependency: transitive
description:
@@ -365,10 +333,10 @@ packages:
dependency: transitive
description:
name: ffi
- sha256: "13a6ccf6a459a125b3fcdb6ec73bd5ff90822e071207c663bfd1f70062d51d18"
+ sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
url: "https://pub.dev"
source: hosted
- version: "1.2.1"
+ version: "2.1.0"
file:
dependency: transitive
description:
@@ -381,10 +349,10 @@ packages:
dependency: transitive
description:
name: fixnum
- sha256: "04be3e934c52e082558cc9ee21f42f5c1cd7a1262f4c63cd0357c08d5bba81ec"
+ sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
url: "https://pub.dev"
source: hosted
- version: "1.0.1"
+ version: "1.1.0"
flutter:
dependency: "direct main"
description: flutter
@@ -394,10 +362,10 @@ packages:
dependency: "direct main"
description:
name: flutter_bloc
- sha256: "890c51c8007f0182360e523518a0c732efb89876cb4669307af7efada5b55557"
+ sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae
url: "https://pub.dev"
source: hosted
- version: "8.1.1"
+ version: "8.1.3"
flutter_driver:
dependency: transitive
description: flutter
@@ -407,26 +375,26 @@ packages:
dependency: "direct main"
description:
name: flutter_hooks
- sha256: "2b202559a4ed3656bbb7aae9d8b335fb0037b23acc7ae3f377d1ba0b95c21aec"
+ sha256: "7c8db779c2d1010aa7f9ea3fbefe8f86524fcb87b69e8b0af31e1a4b55422dec"
url: "https://pub.dev"
source: hosted
- version: "0.18.5+1"
+ version: "0.20.3"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
- sha256: "559c600f056e7c704bd843723c21e01b5fba47e8824bd02422165bcc02a5de1d"
+ sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
url: "https://pub.dev"
source: hosted
- version: "0.9.3"
+ version: "0.13.1"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
- sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
+ sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
url: "https://pub.dev"
source: hosted
- version: "2.0.1"
+ version: "3.0.1"
flutter_list_view:
dependency: "direct main"
description:
@@ -444,50 +412,50 @@ packages:
dependency: "direct main"
description:
name: flutter_secure_storage
- sha256: "5abe3d5c25ab435e48c47fb61bac25606062a305fac637c2f020e25abd30014a"
+ sha256: ffdbb60130e4665d2af814a0267c481bcf522c41ae2e43caf69fa0146876d685
url: "https://pub.dev"
source: hosted
- version: "5.1.2"
+ version: "9.0.0"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
- sha256: "7b36defaed0a994cc58d6a169a7c89c695ea660ef86903df13c2a2708fb1e1bb"
+ sha256: "3d5032e314774ee0e1a7d0a9f5e2793486f0dff2dd9ef5a23f4e3fb2a0ae6a9e"
url: "https://pub.dev"
source: hosted
- version: "1.1.1"
+ version: "1.2.0"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
- sha256: cd8eff6ebb4d9083aa3a57f29da00df837a869e8d5c65d9ad1ce549037c55d06
+ sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c
url: "https://pub.dev"
source: hosted
- version: "1.1.1"
+ version: "3.0.1"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
- sha256: "9af003dec5ba9f959300fd76ac8adf5608fbfbc957cdd7a987af206a8e073b32"
+ sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e"
url: "https://pub.dev"
source: hosted
- version: "1.0.0"
+ version: "1.0.2"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
- sha256: "926716d84eb45220cb1783af629093301613f5e5b51da7c1813e430d69bd716f"
+ sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20"
url: "https://pub.dev"
source: hosted
- version: "1.0.2"
+ version: "1.1.2"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
- sha256: cf9fd49c2807f80dc01f449592e1e7971a3697d1e248b653efb8323536dc2961
+ sha256: "5809c66f9dd3b4b93b0a6e2e8561539405322ee767ac2f64d084e2ab5429d108"
url: "https://pub.dev"
source: hosted
- version: "1.1.2"
+ version: "3.0.0"
flutter_share:
dependency: "direct main"
description:
@@ -500,18 +468,18 @@ packages:
dependency: "direct main"
description:
name: flutter_sliding_up_panel
- sha256: "60fdb281d2a81047dadecb931f9b53b6f7189680cd71f898441073207ff90e6f"
+ sha256: "94f928973d83e146bbc52051e2d9f2a7ed7a5c9e7f04b54d835fff2e41d6cb99"
url: "https://pub.dev"
source: hosted
- version: "2.0.1"
+ version: "2.1.1"
flutter_svg:
dependency: "direct main"
description:
name: flutter_svg
- sha256: f2aa23d9d1721cd5c2c5097558368d2a1f85be35a85a6cf26a626e80c369a47c
+ sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c
url: "https://pub.dev"
source: hosted
- version: "1.1.5"
+ version: "2.0.9"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -521,10 +489,10 @@ packages:
dependency: "direct main"
description:
name: flutter_web_auth
- sha256: "1becc47ee73009e9ea19402e2194c35dda2b2fbbe2023894df97c8caa4781335"
+ sha256: a69fa8f43b9e4d86ac72176bf747b735e7b977dd7cf215076d95b87cb05affdd
url: "https://pub.dev"
source: hosted
- version: "0.4.1"
+ version: "0.5.0"
flutter_web_plugins:
dependency: transitive
description: flutter
@@ -534,26 +502,26 @@ packages:
dependency: "direct dev"
description:
name: freezed
- sha256: b8f1017d491344ef41045d3fe85950404c49e74eeaf84a84d7b8b67ac24dfb91
+ sha256: "6c5031daae12c7072b3a87eff98983076434b4889ef2a44384d0cae3f82372ba"
url: "https://pub.dev"
source: hosted
- version: "2.1.0+1"
+ version: "2.4.6"
freezed_annotation:
dependency: "direct main"
description:
name: freezed_annotation
- sha256: "625eb228fd9f00f952b7cd245be34791434fad48375f74e46f97dea4b4e11678"
+ sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d
url: "https://pub.dev"
source: hosted
- version: "2.1.0"
+ version: "2.4.1"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
- sha256: "4f4a162323c86ffc1245765cfe138872b8f069deb42f7dbb36115fa27f31469b"
+ sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
url: "https://pub.dev"
source: hosted
- version: "2.1.3"
+ version: "3.2.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
@@ -563,26 +531,26 @@ packages:
dependency: transitive
description:
name: glob
- sha256: c51b4fdfee4d281f49b8c957f1add91b815473597f76bcf07377987f66a55729
+ sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
- version: "2.1.0"
+ version: "2.1.2"
google_fonts:
dependency: "direct main"
description:
name: google_fonts
- sha256: "8f099045e2f2a30e4d4d0a35f40c6bc941a8f2ca0e10ad9d214ee9edd3f37483"
+ sha256: f0b8d115a13ecf827013ec9fc883390ccc0e87a96ed5347a3114cac177ef18e8
url: "https://pub.dev"
source: hosted
- version: "3.0.1"
+ version: "6.1.0"
graphs:
dependency: transitive
description:
name: graphs
- sha256: ae0b3d956ff324c6f8671f08dcb2dbd71c99cdbf2aa3ca63a14190c47aa6679c
+ sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
url: "https://pub.dev"
source: hosted
- version: "2.1.0"
+ version: "2.3.1"
hive:
dependency: "direct main"
description:
@@ -603,26 +571,18 @@ packages:
dependency: "direct dev"
description:
name: hive_generator
- sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.3"
- html:
- dependency: transitive
- description:
- name: html
- sha256: bfef906cbd4e78ef49ae511d9074aebd1d2251482ef601a280973e8b58b51bbf
+ sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
url: "https://pub.dev"
source: hosted
- version: "0.15.0"
+ version: "2.0.1"
http:
dependency: "direct main"
description:
name: http
- sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482"
+ sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
url: "https://pub.dev"
source: hosted
- version: "0.13.5"
+ version: "1.1.2"
http_multi_server:
dependency: transitive
description:
@@ -635,26 +595,26 @@ packages:
dependency: transitive
description:
name: http_parser
- sha256: db3060f22889f3d9d55f6a217565486737037eec3609f7f3eca4d0c67ee0d8a0
+ sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
- version: "4.0.1"
+ version: "4.0.2"
image:
dependency: transitive
description:
name: image
- sha256: "9d2c5f73435a70a936d317769ee8e7ef480e37674b9f2bce95ea98969a307855"
+ sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271"
url: "https://pub.dev"
source: hosted
- version: "3.2.0"
+ version: "4.1.3"
implicitly_animated_list:
dependency: transitive
description:
name: implicitly_animated_list
- sha256: eb87227f9d55ac2d927ea8c2ef59b6cd24cada87f869a7a584c1c9e07cbf35c6
+ sha256: "327074913ed350fbd5089bf433d6268fb98022210e03668035523da7ff64dfdb"
url: "https://pub.dev"
source: hosted
- version: "2.1.0"
+ version: "2.2.0"
integration_test:
dependency: "direct dev"
description: flutter
@@ -664,50 +624,58 @@ packages:
dependency: "direct main"
description:
name: intl
- sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91"
+ sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev"
source: hosted
- version: "0.17.0"
+ version: "0.18.1"
io:
dependency: transitive
description:
name: io
- sha256: "0d4c73c3653ab85bf696d51a9657604c900a370549196a91f33e4c39af760852"
+ sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
url: "https://pub.dev"
source: hosted
- version: "1.0.3"
+ version: "1.0.4"
js:
dependency: transitive
description:
name: js
- sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
+ sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
- version: "0.6.5"
+ version: "0.6.7"
json_annotation:
dependency: "direct main"
description:
name: json_annotation
- sha256: cb314f00b2488de7bc575207e54402cd2f92363f333a7933fd1b0631af226baa
+ sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
url: "https://pub.dev"
source: hosted
- version: "4.6.0"
+ version: "4.8.1"
json_serializable:
dependency: "direct dev"
description:
name: json_serializable
- sha256: "0cec7060459254cf1ff980c08dedca6fa50917724a3c3ec8c5026cb88dee8238"
+ sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969
url: "https://pub.dev"
source: hosted
- version: "6.3.1"
+ version: "6.7.1"
+ json_view:
+ dependency: transitive
+ description:
+ name: json_view
+ sha256: "905c69f9e69d1eab5406b87ab6c10c3706c04c70c6a4959621bd2b43c2d27374"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.4.2"
lints:
dependency: transitive
description:
name: lints
- sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3"
+ sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
- version: "2.0.0"
+ version: "3.0.0"
list_diff:
dependency: transitive
description:
@@ -720,50 +688,50 @@ packages:
dependency: transitive
description:
name: logging
- sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946
+ sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
url: "https://pub.dev"
source: hosted
- version: "1.1.0"
+ version: "1.2.0"
matcher:
dependency: transitive
description:
name: matcher
- sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
+ sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
- version: "0.12.13"
+ version: "0.12.16"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
- sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
+ sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
- version: "0.2.0"
+ version: "0.5.0"
meta:
dependency: transitive
description:
name: meta
- sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
+ sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
url: "https://pub.dev"
source: hosted
- version: "1.8.0"
+ version: "1.10.0"
mime:
dependency: transitive
description:
name: mime
- sha256: dab22e92b41aa1255ea90ddc4bc2feaf35544fd0728e209638cad041a6e3928a
+ sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
url: "https://pub.dev"
source: hosted
- version: "1.0.2"
+ version: "1.0.4"
mocktail:
dependency: "direct dev"
description:
name: mocktail
- sha256: "80a996cd9a69284b3dc521ce185ffe9150cde69767c2d3a0720147d93c0cef53"
+ sha256: f603ebd85a576e5914870b02e5839fc5d0243b867bf710651cf239a28ebb365e
url: "https://pub.dev"
source: hosted
- version: "0.3.0"
+ version: "1.0.2"
nested:
dependency: transitive
description:
@@ -776,10 +744,10 @@ packages:
dependency: transitive
description:
name: node_preamble
- sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d"
+ sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
- version: "2.0.1"
+ version: "2.0.2"
overlay_dialog:
dependency: "direct main"
description:
@@ -800,66 +768,26 @@ packages:
dependency: transitive
description:
name: package_info_plus
- sha256: "7a6114becdf042be2b0777d77ace954d4a205644171a1cbd8712976b9bbb837c"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.2"
- package_info_plus_linux:
- dependency: transitive
- description:
- name: package_info_plus_linux
- sha256: "04b575f44233d30edbb80a94e57cad9107aada334fc02aabb42b6becd13c43fc"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.5"
- package_info_plus_macos:
- dependency: transitive
- description:
- name: package_info_plus_macos
- sha256: a2ad8b4acf4cd479d4a0afa5a74ea3f5b1c7563b77e52cc32b3ee6956d5482a6
+ sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79"
url: "https://pub.dev"
source: hosted
- version: "1.3.0"
+ version: "5.0.1"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
- sha256: f7a0c8f1e7e981bc65f8b64137a53fd3c195b18d429fba960babc59a5a1c7ae8
- url: "https://pub.dev"
- source: hosted
- version: "1.0.2"
- package_info_plus_web:
- dependency: transitive
- description:
- name: package_info_plus_web
- sha256: f0829327eb534789e0a16ccac8936a80beed4e2401c4d3a74f3f39094a822d3b
+ sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
url: "https://pub.dev"
source: hosted
- version: "1.0.6"
- package_info_plus_windows:
- dependency: transitive
- description:
- name: package_info_plus_windows
- sha256: a6040b8695c82f8dd3c3d4dfab7ef96fbe9c67aac21b9bcf5db272589ef84441
- url: "https://pub.dev"
- source: hosted
- version: "1.0.5"
+ version: "2.0.1"
path:
dependency: transitive
description:
name: path
- sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
+ sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev"
source: hosted
- version: "1.8.2"
- path_drawing:
- dependency: transitive
- description:
- name: path_drawing
- sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977
- url: "https://pub.dev"
- source: hosted
- version: "1.0.1"
+ version: "1.8.3"
path_parsing:
dependency: transitive
description:
@@ -872,90 +800,90 @@ packages:
dependency: "direct main"
description:
name: path_provider
- sha256: "050e8e85e4b7fecdf2bb3682c1c64c4887a183720c802d323de8a5fd76d372dd"
+ sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
url: "https://pub.dev"
source: hosted
- version: "2.0.11"
+ version: "2.1.1"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
- sha256: "4d5542667150f5b779ba411dd5dc0b674a85d1355e45bda2877e0e82f4ad08d8"
+ sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
url: "https://pub.dev"
source: hosted
- version: "2.0.20"
- path_provider_ios:
+ version: "2.2.1"
+ path_provider_foundation:
dependency: transitive
description:
- name: path_provider_ios
- sha256: "03d639406f5343478352433f00d3c4394d52dac8df3d847869c5e2333e0bbce8"
+ name: path_provider_foundation
+ sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
url: "https://pub.dev"
source: hosted
- version: "2.0.11"
+ version: "2.3.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
- sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379
- url: "https://pub.dev"
- source: hosted
- version: "2.1.7"
- path_provider_macos:
- dependency: transitive
- description:
- name: path_provider_macos
- sha256: "2a97e7fbb7ae9dcd0dfc1220a78e9ec3e71da691912e617e8715ff2a13086ae8"
+ sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
- version: "2.0.6"
+ version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
- sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76
+ sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
url: "https://pub.dev"
source: hosted
- version: "2.0.5"
+ version: "2.1.1"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
- sha256: a34ecd7fb548f8e57321fd8e50d865d266941b54e6c3b7758cf8f37c24116905
+ sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
url: "https://pub.dev"
source: hosted
- version: "2.0.7"
+ version: "2.2.1"
pdf:
dependency: "direct main"
description:
name: pdf
- sha256: "47bcb9818427d099ccc8bea7608eef8fc0e3a6bfd9c2370565361ea78eabf6bf"
+ sha256: "93cbb2c06de9bab91844550f19896b2373e7a5ce25173995e7e5ec5e1741429d"
url: "https://pub.dev"
source: hosted
- version: "3.8.3"
+ version: "3.10.7"
petitparser:
dependency: transitive
description:
name: petitparser
- sha256: "2ebb289dc4764ec397f5cd3ca9881c6d17196130a7d646ed022a0dd9c2e25a71"
+ sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
- version: "5.0.0"
+ version: "6.0.2"
platform:
dependency: transitive
description:
name: platform
- sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
+ sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102
url: "https://pub.dev"
source: hosted
- version: "3.1.0"
+ version: "3.1.2"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
- sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a
+ sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
url: "https://pub.dev"
source: hosted
- version: "2.1.3"
+ version: "2.1.7"
+ pointycastle:
+ dependency: transitive
+ description:
+ name: pointycastle
+ sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.7.3"
pool:
dependency: transitive
description:
@@ -964,22 +892,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
- popover:
- dependency: "direct main"
- description:
- name: popover
- sha256: "4255a09e3bb64cada6aebdeeeb15453a2790802d4eecb9256ff5c895863582ea"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.8+1"
printing:
dependency: "direct main"
description:
name: printing
- sha256: "4df9e22bd4cb2ecea67183e5b328711b10276127b8878d9d5cb60ccd4c24a77c"
+ sha256: ad39a42a5f83125952457dfd94f395c8cf0eb1f7759583dadb769be5c7f99d24
url: "https://pub.dev"
source: hosted
- version: "5.9.3"
+ version: "5.11.1"
process:
dependency: transitive
description:
@@ -1000,18 +920,18 @@ packages:
dependency: transitive
description:
name: pub_semver
- sha256: "816c1a640e952d213ddd223b3e7aafae08cd9f8e1f6864eed304cc13b0272b07"
+ sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
url: "https://pub.dev"
source: hosted
- version: "2.1.1"
+ version: "2.1.4"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
- sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a"
+ sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
url: "https://pub.dev"
source: hosted
- version: "1.2.1"
+ version: "1.2.3"
qr:
dependency: transitive
description:
@@ -1032,10 +952,10 @@ packages:
dependency: transitive
description:
name: sensors_plus_platform_interface
- sha256: dde5184f72b56b25a19d5d88a27154bedf5c3fb9584def621d0d320b613c8d09
+ sha256: bc472d6cfd622acb4f020e726433ee31788b038056691ba433fec80e448a094f
url: "https://pub.dev"
source: hosted
- version: "1.1.2"
+ version: "1.2.0"
sensors_plus_web:
dependency: transitive
description:
@@ -1048,106 +968,98 @@ packages:
dependency: transitive
description:
name: shake
- sha256: "4c3b9477d72b88e5108a3f13c8cadfa83355bed50b26087166628602f4e261af"
+ sha256: "107546951c6b8f5e4c2dca66dfb3aa27dd1a853b4e9a26c9aea224b167045023"
url: "https://pub.dev"
source: hosted
- version: "2.1.0"
+ version: "2.2.0"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
- sha256: "76917b7d4b9526b2ba416808a7eb9fb2863c1a09cf63ec85f1453da240fa818a"
+ sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
url: "https://pub.dev"
source: hosted
- version: "2.0.15"
+ version: "2.2.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
- sha256: "3e128864b9cff21bdd5b3ad569953070a851d62901bee880bb052b1110b38007"
+ sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
url: "https://pub.dev"
source: hosted
- version: "2.0.13"
- shared_preferences_ios:
+ version: "2.2.1"
+ shared_preferences_foundation:
dependency: transitive
description:
- name: shared_preferences_ios
- sha256: "585a14cefec7da8c9c2fb8cd283a3bb726b4155c0952afe6a0caaa7b2272de34"
+ name: shared_preferences_foundation
+ sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
url: "https://pub.dev"
source: hosted
- version: "2.1.1"
+ version: "2.3.4"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
- sha256: "28aefc1261746e7bad3d09799496054beb84e8c4ffcdfed7734e17b4ada459a5"
+ sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
url: "https://pub.dev"
source: hosted
- version: "2.1.1"
- shared_preferences_macos:
- dependency: transitive
- description:
- name: shared_preferences_macos
- sha256: fbb94bf296576f49be37a1496d5951796211a8db0aa22cc0d68c46440dad808c
- url: "https://pub.dev"
- source: hosted
- version: "2.0.4"
+ version: "2.3.2"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
- sha256: da9431745ede5ece47bc26d5d73a9d3c6936ef6945c101a5aca46f62e52c1cf3
+ sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
url: "https://pub.dev"
source: hosted
- version: "2.1.0"
+ version: "2.3.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
- sha256: a4b5bc37fe1b368bbc81f953197d55e12f49d0296e7e412dfe2d2d77d6929958
+ sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
url: "https://pub.dev"
source: hosted
- version: "2.0.4"
+ version: "2.2.2"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
- sha256: "97f7ab9a7da96d9cf19581f5de520ceb529548498bd6b5e0ccd02d68a0d15eba"
+ sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
url: "https://pub.dev"
source: hosted
- version: "2.1.1"
+ version: "2.3.2"
shelf:
dependency: transitive
description:
name: shelf
- sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c
+ sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
url: "https://pub.dev"
source: hosted
- version: "1.4.0"
+ version: "1.4.1"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
- sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306
+ sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
- version: "3.0.1"
+ version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
- sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c
+ sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
url: "https://pub.dev"
source: hosted
- version: "1.1.1"
+ version: "1.1.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
- sha256: "6db16374bc3497d21aa0eebe674d3db9fdf82082aac0f04dc7b44e4af5b08afc"
+ sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
url: "https://pub.dev"
source: hosted
- version: "1.0.2"
+ version: "1.0.4"
sky_engine:
dependency: transitive
description: flutter
@@ -1157,66 +1069,66 @@ packages:
dependency: transitive
description:
name: source_gen
- sha256: "00f8b6b586f724a8c769c96f1d517511a41661c0aede644544d8d86a1ab11142"
+ sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
url: "https://pub.dev"
source: hosted
- version: "1.2.2"
+ version: "1.5.0"
source_helper:
dependency: transitive
description:
name: source_helper
- sha256: "522d9b05c40ec14f479ce4428337d106c0465fedab42f514582c198460a784fe"
+ sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd"
url: "https://pub.dev"
source: hosted
- version: "1.3.2"
+ version: "1.3.4"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
- sha256: "8c463326277f68a628abab20580047b419c2ff66756fd0affd451f73f9508c11"
+ sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae"
url: "https://pub.dev"
source: hosted
- version: "2.1.0"
+ version: "2.1.1"
source_maps:
dependency: transitive
description:
name: source_maps
- sha256: "52de2200bb098de739794c82d09c41ac27b2e42fd7e23cce7b9c74bf653c7296"
+ sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
url: "https://pub.dev"
source: hosted
- version: "0.10.10"
+ version: "0.10.12"
source_span:
dependency: transitive
description:
name: source_span
- sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
+ sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
- version: "1.9.1"
+ version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
- sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
+ sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
- version: "1.11.0"
+ version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
- sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
+ sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
- version: "2.1.1"
+ version: "2.1.2"
stream_transform:
dependency: transitive
description:
name: stream_transform
- sha256: f1d172e22a5432c042b5adfa9aff621372e4292231d9d73ad00f486ad01c2395
+ sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
url: "https://pub.dev"
source: hosted
- version: "2.0.1"
+ version: "2.1.0"
string_scanner:
dependency: transitive
description:
@@ -1245,130 +1157,146 @@ packages:
dependency: transitive
description:
name: test
- sha256: a5fcd2d25eeadbb6589e80198a47d6a464ba3e2049da473943b8af9797900c2d
+ sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f
url: "https://pub.dev"
source: hosted
- version: "1.22.0"
+ version: "1.24.9"
test_api:
dependency: transitive
description:
name: test_api
- sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
+ sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev"
source: hosted
- version: "0.4.16"
+ version: "0.6.1"
test_core:
dependency: transitive
description:
name: test_core
- sha256: "0ef9755ec6d746951ba0aabe62f874b707690b5ede0fecc818b138fcc9b14888"
+ sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a
url: "https://pub.dev"
source: hosted
- version: "0.4.20"
+ version: "0.5.9"
time:
dependency: transitive
description:
name: time
- sha256: "267028bb7b3e87bbfd66876c6389d7101e4b14eb94fe863d3e008e497ca07844"
+ sha256: "83427e11d9072e038364a5e4da559e85869b227cf699a541be0da74f14140124"
url: "https://pub.dev"
source: hosted
- version: "2.1.2"
+ version: "2.1.3"
timing:
dependency: transitive
description:
name: timing
- sha256: c386d07d7f5efc613479a7c4d9d64b03710b03cfaa7e8ad5f2bfb295a1f0dfad
+ sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
url: "https://pub.dev"
source: hosted
- version: "1.0.0"
+ version: "1.0.1"
typed_data:
dependency: transitive
description:
name: typed_data
- sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
+ sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
- version: "1.3.1"
- universal_html:
- dependency: transitive
- description:
- name: universal_html
- sha256: "5ff50b7c14d201421cf5230ec389a0591c4deb5c817c9d7ccca3b26fe5f31e34"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.8"
+ version: "1.3.2"
universal_io:
dependency: transitive
description:
name: universal_io
- sha256: "79f78ddad839ee3aae3ec7c01eb4575faf0d5c860f8e5223bc9f9c17f7f03cef"
+ sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
url: "https://pub.dev"
source: hosted
- version: "2.0.4"
+ version: "2.2.2"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
- sha256: "568176fc8ab5ac1d88ff0db8ff28659d103851670dda55e83b485664c2309299"
+ sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86
url: "https://pub.dev"
source: hosted
- version: "6.1.6"
+ version: "6.2.2"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
- sha256: "9e262cbec69233717d5198f4d0b0c4961fa027e3685ba425442c43c64f38bb9b"
+ sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def"
url: "https://pub.dev"
source: hosted
- version: "6.0.19"
+ version: "6.2.0"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
- sha256: "6ba7dddee26c9fae27c9203c424631109d73c8fa26cfa7bc3e35e751cb87f62e"
+ sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
url: "https://pub.dev"
source: hosted
- version: "6.0.17"
+ version: "6.2.1"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
- sha256: "360fa359ab06bcb4f7c5cd3123a2a9a4d3364d4575d27c4b33468bd4497dd094"
+ sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811
url: "https://pub.dev"
source: hosted
- version: "3.0.1"
+ version: "3.1.1"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
- sha256: a9b3ea9043eabfaadfa3fb89de67a11210d85569086d22b3854484beab8b3978
+ sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
url: "https://pub.dev"
source: hosted
- version: "3.0.1"
+ version: "3.1.0"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
- sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6"
+ sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50"
url: "https://pub.dev"
source: hosted
- version: "2.1.1"
+ version: "2.2.0"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
- sha256: "5669882643b96bb6d5786637cac727c6e918a790053b09245fd4513b8a07df2a"
+ sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9"
url: "https://pub.dev"
source: hosted
- version: "2.0.13"
+ version: "2.2.2"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
- sha256: e3c3b16d3104260c10eea3b0e34272aaa57921f83148b0619f74c2eced9b7ef1
+ sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7
url: "https://pub.dev"
source: hosted
- version: "3.0.1"
+ version: "3.1.1"
+ vector_graphics:
+ dependency: transitive
+ description:
+ name: vector_graphics
+ sha256: "0f0c746dd2d6254a0057218ff980fc7f5670fd0fcf5e4db38a490d31eed4ad43"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.9+1"
+ vector_graphics_codec:
+ dependency: transitive
+ description:
+ name: vector_graphics_codec
+ sha256: "0edf6d630d1bfd5589114138ed8fada3234deacc37966bec033d3047c29248b7"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.9+1"
+ vector_graphics_compiler:
+ dependency: transitive
+ description:
+ name: vector_graphics_compiler
+ sha256: d24333727332d9bd20990f1483af4e09abdb9b1fc7c3db940b56ab5c42790c26
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.9+1"
vector_math:
dependency: transitive
description:
@@ -1381,66 +1309,82 @@ packages:
dependency: transitive
description:
name: vm_service
- sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7
+ sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583
url: "https://pub.dev"
source: hosted
- version: "9.4.0"
+ version: "11.10.0"
watcher:
dependency: transitive
description:
name: watcher
- sha256: e42dfcc48f67618344da967b10f62de57e04bae01d9d3af4c2596f3712a88c99
+ sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
- version: "1.0.1"
+ version: "1.1.0"
+ web:
+ dependency: transitive
+ description:
+ name: web
+ sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.0"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
- sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd"
+ sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
url: "https://pub.dev"
source: hosted
- version: "2.2.0"
+ version: "2.4.0"
webdriver:
dependency: transitive
description:
name: webdriver
- sha256: ef67178f0cc7e32c1494645b11639dd1335f1d18814aa8435113a92e9ef9d841
+ sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49"
url: "https://pub.dev"
source: hosted
- version: "3.0.1"
+ version: "3.0.2"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
- sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d"
+ sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
- version: "1.2.0"
+ version: "1.2.1"
win32:
dependency: transitive
description:
name: win32
- sha256: c0e3a4f7be7dae51d8f152230b86627e3397c1ba8c3fa58e63d44a9f3edc9cef
+ sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.1.1"
+ win32_registry:
+ dependency: transitive
+ description:
+ name: win32_registry
+ sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a"
url: "https://pub.dev"
source: hosted
- version: "2.6.1"
+ version: "1.1.2"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
- sha256: "11541eedefbcaec9de35aa82650b695297ce668662bbd6e3911a7fabdbde589f"
+ sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
url: "https://pub.dev"
source: hosted
- version: "0.2.0+2"
+ version: "1.0.3"
xml:
dependency: transitive
description:
name: xml
- sha256: ac0e3f4bf00ba2708c33fbabbbe766300e509f8c82dbd4ab6525039813f7e2fb
+ sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
- version: "6.1.0"
+ version: "6.5.0"
yaml:
dependency: transitive
description:
@@ -1450,5 +1394,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
- dart: ">=2.19.0 <3.0.0"
- flutter: ">=3.3.0"
+ dart: ">=3.2.0 <3.3.0"
+ flutter: ">=3.16.0"
diff --git a/app/pubspec.yaml b/app/pubspec.yaml
index 6a2f63f3c..fd758c4de 100644
--- a/app/pubspec.yaml
+++ b/app/pubspec.yaml
@@ -4,61 +4,60 @@ publish_to: 'none'
version: 1.0.0+1
environment:
- sdk: '>=2.17.0 <3.0.0'
- flutter: '>=3.0.0 <3.1.0'
+ sdk: '>=2.17.0 <3.3.0'
+ flutter: '>=3.3.0'
dependencies:
- auto_route: ^4.2.0
+ auto_route: ^7.8.4
auto_size_text: ^3.0.0
- black_hole_flutter: ^0.3.5
+ black_hole_flutter: ^1.1.0
bloc: ^8.0.3
collection: ^1.16.0
cupertino_icons: ^1.0.5
dartx: ^1.1.0
- debug_overlay: ^0.1.4
- dropdown_button2: ^1.6.2
+ debug_overlay: ^0.2.11
+ dropdown_button2: ^2.3.9
flutter:
sdk: flutter
flutter_bloc: ^8.0.1
- flutter_hooks: ^0.18.5+1
+ flutter_hooks: ^0.20.3
flutter_list_view: ^1.1.22
flutter_localizations:
sdk: flutter
- flutter_secure_storage: ^5.0.2
+ flutter_secure_storage: ^9.0.0
flutter_share: ^2.0.0
flutter_sliding_up_panel: ^2.0.1
- flutter_svg: ^1.1.1
- flutter_web_auth: ^0.4.1
+ flutter_svg: ^2.0.9
+ flutter_web_auth: ^0.5.0
freezed_annotation: ^2.0.3
- google_fonts: ^3.0.1
+ google_fonts: ^6.1.0
hive: ^2.2.2
hive_flutter: ^1.1.0
- http: ^0.13.4
- intl: ^0.17.0
+ http: ^1.1.2
+ intl: ^0.18.1
json_annotation: ^4.6.0
overlay_dialog: ^0.2.2
path_provider: ^2.0.11
pdf: ^3.8.1
- popover: ^0.2.8+1
printing: ^5.9.3
provider: ^6.1.1
shared_preferences: ^2.0.15
url_launcher: ^6.1.4
dev_dependencies:
- auto_route_generator: ^4.2.0
+ auto_route_generator: ^7.3.2
bloc_test: ^9.0.3
build_runner: ^2.1.11
- flutter_launcher_icons: ^0.9.3
- flutter_lints: ^2.0.1
+ flutter_launcher_icons: ^0.13.1
+ flutter_lints: ^3.0.1
flutter_test:
sdk: flutter
freezed: ^2.0.3+1
- hive_generator: ^1.1.3
+ hive_generator: ^2.0.1
integration_test:
sdk: flutter
json_serializable: ^6.2.0
- mocktail: ^0.3.0
+ mocktail: ^1.0.2
flutter:
generate: true