From ee62ddf5ce882de94c543dbf9322bc9e852b7db5 Mon Sep 17 00:00:00 2001 From: CHAN Kelwin Hillary <5429312+ckelwin@users.noreply.github.com> Date: Thu, 12 Oct 2023 20:47:39 +0800 Subject: [PATCH 01/23] fix(JordyHers-org/Times-up-flutter#188): Made child picture not mandatory when adding a new child. A default icon will be displayed as a substitute. --- lib/app/pages/child_details_page.dart | 11 ++++---- lib/app/pages/edit_child_page.dart | 39 ++++++++++++++------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/app/pages/child_details_page.dart b/lib/app/pages/child_details_page.dart index 51d9fe1..d61789d 100644 --- a/lib/app/pages/child_details_page.dart +++ b/lib/app/pages/child_details_page.dart @@ -95,12 +95,11 @@ class _ChildDetailsPageState extends State { return [ SliverAppBar( actions: [ - if (model.image != null) - ClipOval( - child: Image.network(model.image!), - ).p4 - else - const SizedBox.shrink(), + ClipOval( + child: model.image != null + ? Image.network(model.image!) + : const Icon(Icons.person), + ).p4, ], elevation: 0.5, shadowColor: CustomColors.indigoLight, diff --git a/lib/app/pages/edit_child_page.dart b/lib/app/pages/edit_child_page.dart index 37f2798..19ce183 100644 --- a/lib/app/pages/edit_child_page.dart +++ b/lib/app/pages/edit_child_page.dart @@ -87,32 +87,33 @@ class _EditChildPageState extends State { Future _submit(XFile? localFile) async { if (appState == AppState.loading) return; if (_validateAndSaveForm()) { - if (localFile == null) return; setState(() { appState = AppState.loading; }); id = uuid.v4().substring(0, 8).toUpperCase(); - try { - final fileExtension = path.extension(localFile.path); - JHLogger.$.d(fileExtension); + if(localFile!=null) { + try { + final fileExtension = path.extension(localFile.path); + JHLogger.$.d(fileExtension); - final firebaseStorageRef = FirebaseStorage.instance - .ref() - .child('Child/"$id"/$id$fileExtension'); + final firebaseStorageRef = FirebaseStorage.instance + .ref() + .child('Child/"$id"/$id$fileExtension'); - await firebaseStorageRef - .putFile(File(localFile.path)) - .catchError((Function onError) { - JHLogger.$.e(onError); - // ignore: return_of_invalid_type_from_catch_error - return false; - }); - final url = await firebaseStorageRef.getDownloadURL(); - _imageURL = url; - JHLogger.$.d('download url: $url'); - } catch (e) { - JHLogger.$.d('...skipping image upload'); + await firebaseStorageRef + .putFile(File(localFile.path)) + .catchError((Function onError) { + JHLogger.$.e(onError); + // ignore: return_of_invalid_type_from_catch_error + return false; + }); + final url = await firebaseStorageRef.getDownloadURL(); + _imageURL = url; + JHLogger.$.d('download url: $url'); + } catch (e) { + JHLogger.$.d('...skipping image upload'); + } } try { From 7ac8f266fc392d348cd65bdfc43f7cef42b5fb2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 12:16:21 +0000 Subject: [PATCH 02/23] chore(deps): bump cupertino_icons from 1.0.5 to 1.0.6 Bumps [cupertino_icons](https://github.com/flutter/packages/tree/main/third_party/packages) from 1.0.5 to 1.0.6. - [Release notes](https://github.com/flutter/packages/releases) - [Commits](https://github.com/flutter/packages/commits/cupertino_icons-v1.0.6/third_party/packages) --- updated-dependencies: - dependency-name: cupertino_icons dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pubspec.lock | 48 ++++++++++++++++++++++++++++-------------------- pubspec.yaml | 2 +- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index e738d9f..c4690d0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -221,10 +221,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" convert: dependency: transitive description: @@ -269,10 +269,10 @@ packages: 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: @@ -905,10 +905,10 @@ packages: dependency: "direct main" description: name: intl - sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" url: "https://pub.dev" source: hosted - version: "0.18.0" + version: "0.18.1" io: dependency: transitive description: @@ -985,18 +985,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + 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: @@ -1017,10 +1017,10 @@ packages: dependency: "direct main" description: name: mockito - sha256: dd61809f04da1838a680926de50a9e87385c1de91c6579629c3d1723946e8059 + sha256: "7d5b53bcd556c1bc7ffbe4e4d5a19c3e112b7e925e9e172dd7c6ad0630812616" url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "5.4.2" mocktail: dependency: "direct dev" description: @@ -1382,10 +1382,10 @@ packages: 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: @@ -1430,26 +1430,26 @@ packages: dependency: "direct main" description: name: test - sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4" + sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" url: "https://pub.dev" source: hosted - version: "1.24.1" + version: "1.24.3" test_api: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" test_core: dependency: transitive description: name: test_core - sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93" + sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.5.3" timezone: dependency: transitive description: @@ -1578,6 +1578,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ed955fa..45154eb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -69,7 +69,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.0 + cupertino_icons: ^1.0.6 freezed_annotation: ^2.2.0 json_annotation: ^4.8.1 From e1684e8285e2946eed8ffa61e83b514b65c9c606 Mon Sep 17 00:00:00 2001 From: jordyhers Date: Wed, 18 Oct 2023 11:32:34 +0200 Subject: [PATCH 03/23] fix: refactor files and position --- lib/app/app.dart | 2 +- .../child_side}/bloc/child_side_bloc.dart | 0 .../child_side}/bloc/child_side_event.dart | 0 .../child_side}/bloc/child_side_state.dart | 0 .../child_side}/child_page.dart | 10 +++--- .../child_side}/set_child_page.dart | 10 +++--- lib/app/{ => features}/landing_page.dart | 8 ++--- .../parent_side}/child_details_page.dart | 22 ++++++------ .../parent_side}/edit_child_page.dart | 10 +++--- .../parent_side/map_page.dart} | 20 +++++------ .../parent_side}/notification_page.dart | 6 ++-- .../parent_side}/parent_page.dart | 35 ++++++++++--------- .../parent_side}/setting_page.dart | 8 ++--- .../features}/sign_in/email_sign_in_bloc.dart | 5 ++- .../email_sign_in_form_bloc_based.dart | 8 ++--- .../sign_in/email_sign_in_model.dart | 2 +- .../features}/sign_in/email_sign_in_page.dart | 2 +- .../sign_in/phone_sign_bloc_based.dart | 0 .../features}/sign_in/sign_in_button.dart | 4 +-- .../features}/sign_in/sign_in_manager.dart | 0 .../features}/sign_in/sign_in_page.dart | 15 ++++---- .../sign_in/social_sign_in_button.dart | 4 +-- .../features}/sign_in/validators.dart | 0 .../{ => features}/splash/splash_content.dart | 2 +- .../{ => features}/splash/splash_screen.dart | 8 ++--- .../helpers/marker_generator_helper.dart} | 0 lib/app/helpers/parsing_extension.dart | 2 +- lib/app/lifecycle/life_cycle.dart | 2 +- ...ler_config.dart => screen_controller.dart} | 8 ++--- lib/common_widgets/jh_custom_marker.dart | 19 ---------- lib/models/set_child_model.dart | 21 ----------- lib/services/app_usage_service.dart | 2 +- lib/services/auth.dart | 2 +- lib/services/database.dart | 4 +-- lib/services/device_info_service.dart | 3 -- lib/services/firestore_service.dart | 2 +- lib/services/notification_service.dart | 2 +- .../child_horizontal_view.dart | 4 +-- .../jh_animated_green_dot.dart | 0 .../jh_bar_chart.dart | 2 +- .../jh_battery_widget.dart | 0 .../jh_custom_button.dart | 4 +-- .../jh_custom_raised_button.dart | 0 .../jh_display_text.dart | 0 .../jh_empty_content.dart | 2 +- .../jh_feature_widget.dart | 2 +- .../jh_form_submit_button.dart | 4 +-- .../jh_header.dart | 2 +- .../jh_header_widget.dart | 2 +- .../jh_info_bottom_sheet.dart | 2 +- .../jh_info_box.dart | 2 +- .../jh_info_row_widget.dart | 8 ++--- .../jh_internet_connection_widget.dart | 0 .../jh_loading_widget.dart | 0 .../jh_no_implementation.dart | 4 +-- .../jh_pin_marker.dart | 0 .../jh_progress_bar.dart | 0 .../jh_size_config.dart | 0 .../jh_summary_tile.dart | 6 ++-- .../show_alert_dialog.dart | 4 +-- .../show_bottom_sheet.dart | 0 .../show_exeption_alert.dart | 2 +- .../show_logger.dart | 0 test/app/config/geo_full_test.dart | 6 ++-- test/app/landing_page_test.dart | 6 ++-- test/helpers/test_helpers.dart | 4 +-- test/helpers/test_helpers.mocks.dart | 6 ++-- test/models/set_child_model_test.dart | 20 ----------- test/sign-in/email_sign_in_bloc_test.dart | 4 +-- test/sign-in/sign_in_manager_test.dart | 2 +- test/sign-in/sign_in_page_test.dart | 4 +-- test/validators_test.dart | 14 +------- .../auto_size_text_test.dart | 2 +- .../bar_chart_test.dart | 0 .../custom_raised_button_test.dart | 2 +- .../empty_content_test.dart | 2 +- .../feature_widget_test.dart | 0 .../loading_map_test.dart | 0 .../show_alert_dialog.dart | 0 79 files changed, 147 insertions(+), 223 deletions(-) rename lib/app/{ => features/child_side}/bloc/child_side_bloc.dart (100%) rename lib/app/{ => features/child_side}/bloc/child_side_event.dart (100%) rename lib/app/{ => features/child_side}/bloc/child_side_state.dart (100%) rename lib/app/{pages => features/child_side}/child_page.dart (96%) rename lib/app/{pages => features/child_side}/set_child_page.dart (94%) rename lib/app/{ => features}/landing_page.dart (91%) rename lib/app/{pages => features/parent_side}/child_details_page.dart (94%) rename lib/app/{pages => features/parent_side}/edit_child_page.dart (95%) rename lib/app/{config/geo_full.dart => features/parent_side/map_page.dart} (93%) rename lib/app/{pages => features/parent_side}/notification_page.dart (96%) rename lib/app/{pages => features/parent_side}/parent_page.dart (93%) rename lib/app/{pages => features/parent_side}/setting_page.dart (95%) rename lib/{ => app/features}/sign_in/email_sign_in_bloc.dart (94%) rename lib/{ => app/features}/sign_in/email_sign_in_form_bloc_based.dart (95%) rename lib/{ => app/features}/sign_in/email_sign_in_model.dart (96%) rename lib/{ => app/features}/sign_in/email_sign_in_page.dart (89%) rename lib/{ => app/features}/sign_in/phone_sign_bloc_based.dart (100%) rename lib/{ => app/features}/sign_in/sign_in_button.dart (85%) rename lib/{ => app/features}/sign_in/sign_in_manager.dart (100%) rename lib/{ => app/features}/sign_in/sign_in_page.dart (89%) rename lib/{ => app/features}/sign_in/social_sign_in_button.dart (83%) rename lib/{ => app/features}/sign_in/validators.dart (100%) rename lib/app/{ => features}/splash/splash_content.dart (98%) rename lib/app/{ => features}/splash/splash_screen.dart (93%) rename lib/{services/marker_generator_service.dart => app/helpers/marker_generator_helper.dart} (100%) rename lib/app/{config/screencontroller_config.dart => screen_controller.dart} (88%) delete mode 100644 lib/common_widgets/jh_custom_marker.dart delete mode 100644 lib/models/set_child_model.dart delete mode 100644 lib/services/device_info_service.dart rename lib/{common_widgets => widgets}/child_horizontal_view.dart (97%) rename lib/{common_widgets => widgets}/jh_animated_green_dot.dart (100%) rename lib/{common_widgets => widgets}/jh_bar_chart.dart (99%) rename lib/{common_widgets => widgets}/jh_battery_widget.dart (100%) rename lib/{common_widgets => widgets}/jh_custom_button.dart (89%) rename lib/{common_widgets => widgets}/jh_custom_raised_button.dart (100%) rename lib/{common_widgets => widgets}/jh_display_text.dart (100%) rename lib/{common_widgets => widgets}/jh_empty_content.dart (93%) rename lib/{common_widgets => widgets}/jh_feature_widget.dart (96%) rename lib/{common_widgets => widgets}/jh_form_submit_button.dart (79%) rename lib/{common_widgets => widgets}/jh_header.dart (93%) rename lib/{common_widgets => widgets}/jh_header_widget.dart (91%) rename lib/{common_widgets => widgets}/jh_info_bottom_sheet.dart (92%) rename lib/{common_widgets => widgets}/jh_info_box.dart (95%) rename lib/{common_widgets => widgets}/jh_info_row_widget.dart (86%) rename lib/{common_widgets => widgets}/jh_internet_connection_widget.dart (100%) rename lib/{common_widgets => widgets}/jh_loading_widget.dart (100%) rename lib/{common_widgets => widgets}/jh_no_implementation.dart (92%) rename lib/{common_widgets => widgets}/jh_pin_marker.dart (100%) rename lib/{common_widgets => widgets}/jh_progress_bar.dart (100%) rename lib/{common_widgets => widgets}/jh_size_config.dart (100%) rename lib/{common_widgets => widgets}/jh_summary_tile.dart (86%) rename lib/{common_widgets => widgets}/show_alert_dialog.dart (93%) rename lib/{common_widgets => widgets}/show_bottom_sheet.dart (100%) rename lib/{common_widgets => widgets}/show_exeption_alert.dart (87%) rename lib/{common_widgets => widgets}/show_logger.dart (100%) delete mode 100644 test/models/set_child_model_test.dart rename test/{common_widgets => widgets}/auto_size_text_test.dart (91%) rename test/{common_widgets => widgets}/bar_chart_test.dart (100%) rename test/{common_widgets => widgets}/custom_raised_button_test.dart (94%) rename test/{common_widgets => widgets}/empty_content_test.dart (88%) rename test/{common_widgets => widgets}/feature_widget_test.dart (100%) rename test/{common_widgets => widgets}/loading_map_test.dart (100%) rename test/{common_widgets => widgets}/show_alert_dialog.dart (100%) diff --git a/lib/app/app.dart b/lib/app/app.dart index df13bd0..294326a 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/app/config/screencontroller_config.dart'; +import 'package:times_up_flutter/app/screen_controller.dart'; import 'package:times_up_flutter/l10n/l10n.dart'; import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/theme/theme_notifier.dart'; diff --git a/lib/app/bloc/child_side_bloc.dart b/lib/app/features/child_side/bloc/child_side_bloc.dart similarity index 100% rename from lib/app/bloc/child_side_bloc.dart rename to lib/app/features/child_side/bloc/child_side_bloc.dart diff --git a/lib/app/bloc/child_side_event.dart b/lib/app/features/child_side/bloc/child_side_event.dart similarity index 100% rename from lib/app/bloc/child_side_event.dart rename to lib/app/features/child_side/bloc/child_side_event.dart diff --git a/lib/app/bloc/child_side_state.dart b/lib/app/features/child_side/bloc/child_side_state.dart similarity index 100% rename from lib/app/bloc/child_side_state.dart rename to lib/app/features/child_side/bloc/child_side_state.dart diff --git a/lib/app/pages/child_page.dart b/lib/app/features/child_side/child_page.dart similarity index 96% rename from lib/app/pages/child_page.dart rename to lib/app/features/child_side/child_page.dart index ccd7642..21954cf 100644 --- a/lib/app/pages/child_page.dart +++ b/lib/app/features/child_side/child_page.dart @@ -7,18 +7,18 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/app/bloc/child_side_bloc.dart'; +import 'package:times_up_flutter/app/features/child_side/bloc/child_side_bloc.dart'; +import 'package:times_up_flutter/app/features/child_side/set_child_page.dart'; +import 'package:times_up_flutter/app/features/landing_page.dart'; import 'package:times_up_flutter/app/helpers/parsing_extension.dart'; -import 'package:times_up_flutter/app/landing_page.dart'; -import 'package:times_up_flutter/app/pages/set_child_page.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/jh_empty_content.dart'; import 'package:times_up_flutter/models/child_model/child_model.dart'; import 'package:times_up_flutter/models/notification_model/notification_model.dart'; import 'package:times_up_flutter/services/app_usage_service.dart'; import 'package:times_up_flutter/services/database.dart'; import 'package:times_up_flutter/services/geo_locator_service.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_empty_content.dart'; class ChildPage extends StatefulWidget { const ChildPage({ diff --git a/lib/app/pages/set_child_page.dart b/lib/app/features/child_side/set_child_page.dart similarity index 94% rename from lib/app/pages/set_child_page.dart rename to lib/app/features/child_side/set_child_page.dart index a6f334f..c16416b 100644 --- a/lib/app/pages/set_child_page.dart +++ b/lib/app/features/child_side/set_child_page.dart @@ -4,16 +4,16 @@ import 'package:battery_plus/battery_plus.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:times_up_flutter/app/features/child_side/child_page.dart'; import 'package:times_up_flutter/app/helpers/parsing_extension.dart'; -import 'package:times_up_flutter/app/pages/child_page.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/jh_form_submit_button.dart'; -import 'package:times_up_flutter/common_widgets/show_alert_dialog.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; import 'package:times_up_flutter/models/child_model/child_model.dart'; import 'package:times_up_flutter/services/app_usage_service.dart'; import 'package:times_up_flutter/services/database.dart'; import 'package:times_up_flutter/services/geo_locator_service.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_form_submit_button.dart'; +import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; enum AppState { loading, complete } diff --git a/lib/app/landing_page.dart b/lib/app/features/landing_page.dart similarity index 91% rename from lib/app/landing_page.dart rename to lib/app/features/landing_page.dart index 02be44e..2cc8641 100644 --- a/lib/app/landing_page.dart +++ b/lib/app/features/landing_page.dart @@ -2,15 +2,15 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:showcaseview/showcaseview.dart'; -import 'package:times_up_flutter/app/pages/parent_page.dart'; -import 'package:times_up_flutter/app/pages/set_child_page.dart'; -import 'package:times_up_flutter/common_widgets/jh_loading_widget.dart'; +import 'package:times_up_flutter/app/features/child_side/set_child_page.dart'; +import 'package:times_up_flutter/app/features/parent_side/parent_page.dart'; +import 'package:times_up_flutter/app/features/sign_in/sign_in_page.dart'; import 'package:times_up_flutter/services/app_usage_service.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/services/database.dart'; import 'package:times_up_flutter/services/geo_locator_service.dart'; import 'package:times_up_flutter/services/shared_preferences.dart'; -import 'package:times_up_flutter/sign_in/sign_in_page.dart'; +import 'package:times_up_flutter/widgets/jh_loading_widget.dart'; enum AppSide { parent, child } diff --git a/lib/app/pages/child_details_page.dart b/lib/app/features/parent_side/child_details_page.dart similarity index 94% rename from lib/app/pages/child_details_page.dart rename to lib/app/features/parent_side/child_details_page.dart index d5bfb94..71ac156 100644 --- a/lib/app/pages/child_details_page.dart +++ b/lib/app/features/parent_side/child_details_page.dart @@ -10,17 +10,17 @@ import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; import 'package:times_up_flutter/app/helpers/parsing_extension.dart'; -import 'package:times_up_flutter/common_widgets/jh_bar_chart.dart'; -import 'package:times_up_flutter/common_widgets/jh_battery_widget.dart'; -import 'package:times_up_flutter/common_widgets/jh_custom_button.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/jh_empty_content.dart'; -import 'package:times_up_flutter/common_widgets/jh_feature_widget.dart'; -import 'package:times_up_flutter/common_widgets/jh_header_widget.dart'; -import 'package:times_up_flutter/common_widgets/show_alert_dialog.dart'; -import 'package:times_up_flutter/common_widgets/show_bottom_sheet.dart'; -import 'package:times_up_flutter/common_widgets/show_exeption_alert.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/widgets/jh_bar_chart.dart'; +import 'package:times_up_flutter/widgets/jh_battery_widget.dart'; +import 'package:times_up_flutter/widgets/jh_custom_button.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_empty_content.dart'; +import 'package:times_up_flutter/widgets/jh_feature_widget.dart'; +import 'package:times_up_flutter/widgets/jh_header_widget.dart'; +import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; +import 'package:times_up_flutter/widgets/show_bottom_sheet.dart'; +import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; import 'package:times_up_flutter/l10n/l10n.dart'; import 'package:times_up_flutter/models/child_model/child_model.dart'; import 'package:times_up_flutter/models/notification_model/notification_model.dart'; diff --git a/lib/app/pages/edit_child_page.dart b/lib/app/features/parent_side/edit_child_page.dart similarity index 95% rename from lib/app/pages/edit_child_page.dart rename to lib/app/features/parent_side/edit_child_page.dart index bf5bacc..126fdd5 100644 --- a/lib/app/pages/edit_child_page.dart +++ b/lib/app/features/parent_side/edit_child_page.dart @@ -6,11 +6,11 @@ import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:path/path.dart' as path; -import 'package:times_up_flutter/common_widgets/jh_custom_raised_button.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/show_alert_dialog.dart'; -import 'package:times_up_flutter/common_widgets/show_exeption_alert.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/widgets/jh_custom_raised_button.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; +import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; import 'package:times_up_flutter/models/child_model/child_model.dart'; import 'package:times_up_flutter/services/database.dart'; import 'package:times_up_flutter/theme/theme.dart'; diff --git a/lib/app/config/geo_full.dart b/lib/app/features/parent_side/map_page.dart similarity index 93% rename from lib/app/config/geo_full.dart rename to lib/app/features/parent_side/map_page.dart index 15bc992..e7b3f21 100644 --- a/lib/app/config/geo_full.dart +++ b/lib/app/features/parent_side/map_page.dart @@ -8,19 +8,19 @@ import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/common_widgets/jh_animated_green_dot.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/jh_header_widget.dart'; -import 'package:times_up_flutter/common_widgets/jh_pin_marker.dart'; +import 'package:times_up_flutter/app/helpers/marker_generator_helper.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/services/database.dart'; import 'package:times_up_flutter/services/geo_locator_service.dart'; -import 'package:times_up_flutter/services/marker_generator_service.dart'; import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/utils/constants.dart'; +import 'package:times_up_flutter/widgets/jh_animated_green_dot.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_header_widget.dart'; +import 'package:times_up_flutter/widgets/jh_pin_marker.dart'; -class GeoFull extends StatefulWidget { - const GeoFull( +class MapView extends StatefulWidget { + const MapView( this.initialPosition, this.database, this.auth, @@ -46,7 +46,7 @@ class GeoFull extends StatefulWidget { listen: false, ); - return GeoFull( + return MapView( position, database, auth, @@ -56,10 +56,10 @@ class GeoFull extends StatefulWidget { } @override - State createState() => _GeoFullState(); + State createState() => _MapViewState(); } -class _GeoFullState extends State with SingleTickerProviderStateMixin { +class _MapViewState extends State with SingleTickerProviderStateMixin { final Completer _controller = Completer(); late final AnimationController _animationController; final _scaffoldKey = GlobalKey(); diff --git a/lib/app/pages/notification_page.dart b/lib/app/features/parent_side/notification_page.dart similarity index 96% rename from lib/app/pages/notification_page.dart rename to lib/app/features/parent_side/notification_page.dart index 1bba60e..dca18ba 100644 --- a/lib/app/pages/notification_page.dart +++ b/lib/app/features/parent_side/notification_page.dart @@ -4,9 +4,9 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/jh_loading_widget.dart'; -import 'package:times_up_flutter/common_widgets/show_exeption_alert.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_loading_widget.dart'; +import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; import 'package:times_up_flutter/models/notification_model/notification_model.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/services/database.dart'; diff --git a/lib/app/pages/parent_page.dart b/lib/app/features/parent_side/parent_page.dart similarity index 93% rename from lib/app/pages/parent_page.dart rename to lib/app/features/parent_side/parent_page.dart index b3910cc..1b2136c 100644 --- a/lib/app/pages/parent_page.dart +++ b/lib/app/features/parent_side/parent_page.dart @@ -6,21 +6,11 @@ import 'package:geolocator/geolocator.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; import 'package:provider/provider.dart'; import 'package:showcaseview/showcaseview.dart'; -import 'package:times_up_flutter/app/config/geo_full.dart'; +import 'package:times_up_flutter/app/features/parent_side/edit_child_page.dart'; +import 'package:times_up_flutter/app/features/parent_side/map_page.dart'; +import 'package:times_up_flutter/app/features/parent_side/notification_page.dart'; +import 'package:times_up_flutter/app/features/parent_side/setting_page.dart'; import 'package:times_up_flutter/app/helpers/parsing_extension.dart'; -import 'package:times_up_flutter/app/pages/child_details_page.dart'; -import 'package:times_up_flutter/app/pages/edit_child_page.dart'; -import 'package:times_up_flutter/app/pages/notification_page.dart'; -import 'package:times_up_flutter/app/pages/setting_page.dart'; -import 'package:times_up_flutter/common_widgets/child_horizontal_view.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/jh_empty_content.dart'; -import 'package:times_up_flutter/common_widgets/jh_header.dart'; -import 'package:times_up_flutter/common_widgets/jh_header_widget.dart'; -import 'package:times_up_flutter/common_widgets/jh_info_row_widget.dart'; -import 'package:times_up_flutter/common_widgets/jh_loading_widget.dart'; -import 'package:times_up_flutter/common_widgets/jh_summary_tile.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; import 'package:times_up_flutter/l10n/l10n.dart'; import 'package:times_up_flutter/models/child_model/child_model.dart'; import 'package:times_up_flutter/services/api_path.dart'; @@ -32,6 +22,17 @@ import 'package:times_up_flutter/services/notification_service.dart'; import 'package:times_up_flutter/services/shared_preferences.dart'; import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/utils/data.dart'; +import 'package:times_up_flutter/widgets/child_horizontal_view.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_empty_content.dart'; +import 'package:times_up_flutter/widgets/jh_header.dart'; +import 'package:times_up_flutter/widgets/jh_header_widget.dart'; +import 'package:times_up_flutter/widgets/jh_info_row_widget.dart'; +import 'package:times_up_flutter/widgets/jh_loading_widget.dart'; +import 'package:times_up_flutter/widgets/jh_summary_tile.dart'; + +import '../../../widgets/show_logger.dart'; +import 'child_details_page.dart'; typedef ValueList = List>; @@ -303,7 +304,7 @@ class _ParentPageState extends State scrollDirection: Axis.horizontal, itemCount: data.length, itemBuilder: (context, index) { - return Kids( + return ChildListView( imageLocation: data[index]?.image, imageCaption: data[index]?.name, onPressed: () => @@ -340,7 +341,7 @@ class _ParentPageState extends State scrollDirection: Axis.horizontal, itemCount: 3, itemBuilder: (context, index) { - return const Kids(); + return const ChildListView(); }, ); }, @@ -353,7 +354,7 @@ class _ParentPageState extends State return Consumer( builder: (context, position, __) { return position != null - ? GeoFull.create( + ? MapView.create( context, position: position, database: database, diff --git a/lib/app/pages/setting_page.dart b/lib/app/features/parent_side/setting_page.dart similarity index 95% rename from lib/app/pages/setting_page.dart rename to lib/app/features/parent_side/setting_page.dart index 9af90ad..fe9ff79 100644 --- a/lib/app/pages/setting_page.dart +++ b/lib/app/features/parent_side/setting_page.dart @@ -3,10 +3,10 @@ import 'package:flutter/material.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/jh_no_implementation.dart'; -import 'package:times_up_flutter/common_widgets/show_alert_dialog.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_no_implementation.dart'; +import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; import 'package:times_up_flutter/services/app_info_service.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/theme/theme.dart'; diff --git a/lib/sign_in/email_sign_in_bloc.dart b/lib/app/features/sign_in/email_sign_in_bloc.dart similarity index 94% rename from lib/sign_in/email_sign_in_bloc.dart rename to lib/app/features/sign_in/email_sign_in_bloc.dart index 265e752..144e29b 100644 --- a/lib/sign_in/email_sign_in_bloc.dart +++ b/lib/app/features/sign_in/email_sign_in_bloc.dart @@ -1,9 +1,8 @@ import 'dart:async'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/app/features/sign_in/email_sign_in_model.dart'; import 'package:times_up_flutter/services/auth.dart'; - -import 'package:times_up_flutter/sign_in/email_sign_in_model.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; class EmailSignInBloc { EmailSignInBloc({required this.auth}); diff --git a/lib/sign_in/email_sign_in_form_bloc_based.dart b/lib/app/features/sign_in/email_sign_in_form_bloc_based.dart similarity index 95% rename from lib/sign_in/email_sign_in_form_bloc_based.dart rename to lib/app/features/sign_in/email_sign_in_form_bloc_based.dart index f6cd298..9ad8546 100644 --- a/lib/sign_in/email_sign_in_form_bloc_based.dart +++ b/lib/app/features/sign_in/email_sign_in_form_bloc_based.dart @@ -3,12 +3,12 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/common_widgets/jh_form_submit_button.dart'; -import 'package:times_up_flutter/common_widgets/show_exeption_alert.dart'; +import 'package:times_up_flutter/app/features/sign_in/email_sign_in_bloc.dart'; +import 'package:times_up_flutter/app/features/sign_in/email_sign_in_model.dart'; import 'package:times_up_flutter/services/auth.dart'; -import 'package:times_up_flutter/sign_in/email_sign_in_bloc.dart'; -import 'package:times_up_flutter/sign_in/email_sign_in_model.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_form_submit_button.dart'; +import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; class EmailSignInFormBlocBased extends StatefulWidget { const EmailSignInFormBlocBased({ diff --git a/lib/sign_in/email_sign_in_model.dart b/lib/app/features/sign_in/email_sign_in_model.dart similarity index 96% rename from lib/sign_in/email_sign_in_model.dart rename to lib/app/features/sign_in/email_sign_in_model.dart index 258e09c..30d4608 100644 --- a/lib/sign_in/email_sign_in_model.dart +++ b/lib/app/features/sign_in/email_sign_in_model.dart @@ -1,4 +1,4 @@ -import 'package:times_up_flutter/sign_in/validators.dart'; +import 'package:times_up_flutter/app/features/sign_in/validators.dart'; /// This enum takes care of the different states of the sign in form enum EmailSignInFormType { signIn, register } diff --git a/lib/sign_in/email_sign_in_page.dart b/lib/app/features/sign_in/email_sign_in_page.dart similarity index 89% rename from lib/sign_in/email_sign_in_page.dart rename to lib/app/features/sign_in/email_sign_in_page.dart index 006c141..692ab77 100644 --- a/lib/sign_in/email_sign_in_page.dart +++ b/lib/app/features/sign_in/email_sign_in_page.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/sign_in/email_sign_in_form_bloc_based.dart'; +import 'package:times_up_flutter/app/features/sign_in/email_sign_in_form_bloc_based.dart'; import 'package:times_up_flutter/theme/theme.dart'; class EmailSignInPage extends StatelessWidget { diff --git a/lib/sign_in/phone_sign_bloc_based.dart b/lib/app/features/sign_in/phone_sign_bloc_based.dart similarity index 100% rename from lib/sign_in/phone_sign_bloc_based.dart rename to lib/app/features/sign_in/phone_sign_bloc_based.dart diff --git a/lib/sign_in/sign_in_button.dart b/lib/app/features/sign_in/sign_in_button.dart similarity index 85% rename from lib/sign_in/sign_in_button.dart rename to lib/app/features/sign_in/sign_in_button.dart index d96b332..90b42e1 100644 --- a/lib/sign_in/sign_in_button.dart +++ b/lib/app/features/sign_in/sign_in_button.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_custom_raised_button.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_custom_raised_button.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; class SignInButton extends JHCustomRaisedButton { SignInButton({ diff --git a/lib/sign_in/sign_in_manager.dart b/lib/app/features/sign_in/sign_in_manager.dart similarity index 100% rename from lib/sign_in/sign_in_manager.dart rename to lib/app/features/sign_in/sign_in_manager.dart diff --git a/lib/sign_in/sign_in_page.dart b/lib/app/features/sign_in/sign_in_page.dart similarity index 89% rename from lib/sign_in/sign_in_page.dart rename to lib/app/features/sign_in/sign_in_page.dart index 86b945b..e41fdfb 100644 --- a/lib/sign_in/sign_in_page.dart +++ b/lib/app/features/sign_in/sign_in_page.dart @@ -1,15 +1,15 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/show_exeption_alert.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/app/features/sign_in/email_sign_in_page.dart'; +import 'package:times_up_flutter/app/features/sign_in/sign_in_button.dart'; +import 'package:times_up_flutter/app/features/sign_in/sign_in_manager.dart'; +import 'package:times_up_flutter/app/features/sign_in/social_sign_in_button.dart'; import 'package:times_up_flutter/services/auth.dart'; -import 'package:times_up_flutter/sign_in/email_sign_in_page.dart'; -import 'package:times_up_flutter/sign_in/sign_in_button.dart'; -import 'package:times_up_flutter/sign_in/sign_in_manager.dart'; -import 'package:times_up_flutter/sign_in/social_sign_in_button.dart'; import 'package:times_up_flutter/utils/constants.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; class SignInPage extends StatelessWidget { const SignInPage({ @@ -67,7 +67,6 @@ class SignInPage extends StatelessWidget { } Future _signInWithEmail(BuildContext context) async { - JHLogger.$.d('SIGNIN WITH EMAIL =>'); try { await Navigator.of(context).push( MaterialPageRoute( diff --git a/lib/sign_in/social_sign_in_button.dart b/lib/app/features/sign_in/social_sign_in_button.dart similarity index 83% rename from lib/sign_in/social_sign_in_button.dart rename to lib/app/features/sign_in/social_sign_in_button.dart index 07285aa..64db670 100644 --- a/lib/sign_in/social_sign_in_button.dart +++ b/lib/app/features/sign_in/social_sign_in_button.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_custom_raised_button.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_custom_raised_button.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; class SocialSignInButton extends JHCustomRaisedButton { SocialSignInButton({ diff --git a/lib/sign_in/validators.dart b/lib/app/features/sign_in/validators.dart similarity index 100% rename from lib/sign_in/validators.dart rename to lib/app/features/sign_in/validators.dart diff --git a/lib/app/splash/splash_content.dart b/lib/app/features/splash/splash_content.dart similarity index 98% rename from lib/app/splash/splash_content.dart rename to lib/app/features/splash/splash_content.dart index 5b26170..78baeb9 100644 --- a/lib/app/splash/splash_content.dart +++ b/lib/app/features/splash/splash_content.dart @@ -1,8 +1,8 @@ // ignore_for_file: library_private_types_in_public_api import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; class SplashContent extends StatefulWidget { const SplashContent({ diff --git a/lib/app/splash/splash_screen.dart b/lib/app/features/splash/splash_screen.dart similarity index 93% rename from lib/app/splash/splash_screen.dart rename to lib/app/features/splash/splash_screen.dart index 04f3d1d..d410674 100644 --- a/lib/app/splash/splash_screen.dart +++ b/lib/app/features/splash/splash_screen.dart @@ -2,13 +2,13 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:times_up_flutter/app/landing_page.dart'; -import 'package:times_up_flutter/app/splash/splash_content.dart'; -import 'package:times_up_flutter/common_widgets/jh_custom_button.dart'; -import 'package:times_up_flutter/common_widgets/jh_size_config.dart'; +import 'package:times_up_flutter/app/features/landing_page.dart'; +import 'package:times_up_flutter/app/features/splash/splash_content.dart'; import 'package:times_up_flutter/services/shared_preferences.dart'; import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/utils/data.dart'; +import 'package:times_up_flutter/widgets/jh_custom_button.dart'; +import 'package:times_up_flutter/widgets/jh_size_config.dart'; class SplashScreen extends StatefulWidget { const SplashScreen({Key? key, this.context}) : super(key: key); diff --git a/lib/services/marker_generator_service.dart b/lib/app/helpers/marker_generator_helper.dart similarity index 100% rename from lib/services/marker_generator_service.dart rename to lib/app/helpers/marker_generator_helper.dart diff --git a/lib/app/helpers/parsing_extension.dart b/lib/app/helpers/parsing_extension.dart index bf07a0f..4c3c651 100644 --- a/lib/app/helpers/parsing_extension.dart +++ b/lib/app/helpers/parsing_extension.dart @@ -1,5 +1,5 @@ import 'package:intl/intl.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; extension ParseResult on String { String t() { diff --git a/lib/app/lifecycle/life_cycle.dart b/lib/app/lifecycle/life_cycle.dart index ff5ee61..134d12c 100644 --- a/lib/app/lifecycle/life_cycle.dart +++ b/lib/app/lifecycle/life_cycle.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; class JHAppLifeCycleObserver extends WidgetsBindingObserver { @override diff --git a/lib/app/config/screencontroller_config.dart b/lib/app/screen_controller.dart similarity index 88% rename from lib/app/config/screencontroller_config.dart rename to lib/app/screen_controller.dart index 3f6f529..6e3cc3b 100644 --- a/lib/app/config/screencontroller_config.dart +++ b/lib/app/screen_controller.dart @@ -2,13 +2,11 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/app/landing_page.dart'; -import 'package:times_up_flutter/common_widgets/jh_internet_connection_widget.dart'; +import 'package:times_up_flutter/app/features/landing_page.dart'; +import 'package:times_up_flutter/app/features/splash/splash_screen.dart'; import 'package:times_up_flutter/services/internet_connectivity_service.dart'; import 'package:times_up_flutter/services/shared_preferences.dart'; - -// ignore: always_use_package_imports -import '../splash/splash_screen.dart'; +import 'package:times_up_flutter/widgets/jh_internet_connection_widget.dart'; // ignore: must_be_immutable class ScreensController extends StatefulWidget { diff --git a/lib/common_widgets/jh_custom_marker.dart b/lib/common_widgets/jh_custom_marker.dart deleted file mode 100644 index 749e028..0000000 --- a/lib/common_widgets/jh_custom_marker.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:flutter/material.dart'; - -class JHCustomMarker extends StatelessWidget { - const JHCustomMarker({ - required this.markerUrl, - Key? key, - }) : super(key: key); - final String markerUrl; - - @override - Widget build(BuildContext context) { - return Image.network( - markerUrl, - height: 32, - width: 32, - color: Colors.indigo, - ); - } -} diff --git a/lib/models/set_child_model.dart b/lib/models/set_child_model.dart deleted file mode 100644 index d9f7de6..0000000 --- a/lib/models/set_child_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:times_up_flutter/sign_in/validators.dart'; - -class SetChildModel with EmailAndPasswordValidators { - SetChildModel({ - this.name = '', - this.email = '', - }); - - final String name; - final String email; - - SetChildModel copyWith({ - required String? name, - required String? email, - }) { - return SetChildModel( - email: email ?? this.email, - name: name ?? this.name, - ); - } -} diff --git a/lib/services/app_usage_service.dart b/lib/services/app_usage_service.dart index 11acd82..7ec04e6 100644 --- a/lib/services/app_usage_service.dart +++ b/lib/services/app_usage_service.dart @@ -1,10 +1,10 @@ import 'package:flutter/cupertino.dart'; import 'package:installed_apps/app_info.dart'; import 'package:times_up_flutter/app/helpers/parsing_extension.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; import 'package:times_up_flutter/models/child_model/child_model.dart'; import 'package:times_up_flutter/services/app_usage_local_service.dart'; import 'package:times_up_flutter/services/database.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; abstract class AppService { Future getAppUsageService(); diff --git a/lib/services/auth.dart b/lib/services/auth.dart index c27b474..d977b35 100644 --- a/lib/services/auth.dart +++ b/lib/services/auth.dart @@ -4,7 +4,7 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter_login_facebook/flutter_login_facebook.dart'; import 'package:google_sign_in/google_sign_in.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; abstract class AuthBase { User? get currentUser; diff --git a/lib/services/database.dart b/lib/services/database.dart index 5e54f31..189caad 100644 --- a/lib/services/database.dart +++ b/lib/services/database.dart @@ -1,5 +1,5 @@ import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; import 'package:times_up_flutter/models/child_model/child_model.dart'; import 'package:times_up_flutter/models/email_model.dart'; import 'package:times_up_flutter/models/notification_model/notification_model.dart'; @@ -154,7 +154,7 @@ class FireStoreDatabase implements Database { AppUsageService apps, ) async { await apps.getAppUsageService(); - // TODO(jordy): UNCOMMENT THIS TO UPDATE LOCATION + //var point = await geo.getInitialLocation(); //var currentLocation = GeoPoint(point.latitude, point.longitude); diff --git a/lib/services/device_info_service.dart b/lib/services/device_info_service.dart deleted file mode 100644 index 29583dd..0000000 --- a/lib/services/device_info_service.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class DeviceInfoServiceInterface {} - -class DeviceInfoService implements DeviceInfoServiceInterface {} diff --git a/lib/services/firestore_service.dart b/lib/services/firestore_service.dart index 203d9f6..667b5cc 100644 --- a/lib/services/firestore_service.dart +++ b/lib/services/firestore_service.dart @@ -3,7 +3,7 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/foundation.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; typedef QueryBuilder = T Function(Map data); diff --git a/lib/services/notification_service.dart b/lib/services/notification_service.dart index f1351a3..39c0161 100644 --- a/lib/services/notification_service.dart +++ b/lib/services/notification_service.dart @@ -3,7 +3,7 @@ import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -import 'package:times_up_flutter/common_widgets/show_logger.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; const AndroidNotificationChannel channel = AndroidNotificationChannel( 'high_importance_channel', // id diff --git a/lib/common_widgets/child_horizontal_view.dart b/lib/widgets/child_horizontal_view.dart similarity index 97% rename from lib/common_widgets/child_horizontal_view.dart rename to lib/widgets/child_horizontal_view.dart index 8a4bdcb..5f1e157 100644 --- a/lib/common_widgets/child_horizontal_view.dart +++ b/lib/widgets/child_horizontal_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -class Kids extends StatelessWidget { - const Kids({ +class ChildListView extends StatelessWidget { + const ChildListView({ this.imageLocation, this.imageCaption, Key? key, diff --git a/lib/common_widgets/jh_animated_green_dot.dart b/lib/widgets/jh_animated_green_dot.dart similarity index 100% rename from lib/common_widgets/jh_animated_green_dot.dart rename to lib/widgets/jh_animated_green_dot.dart diff --git a/lib/common_widgets/jh_bar_chart.dart b/lib/widgets/jh_bar_chart.dart similarity index 99% rename from lib/common_widgets/jh_bar_chart.dart rename to lib/widgets/jh_bar_chart.dart index 4977e05..b558226 100644 --- a/lib/common_widgets/jh_bar_chart.dart +++ b/lib/widgets/jh_bar_chart.dart @@ -2,7 +2,7 @@ import 'dart:math'; import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; class JHAppUsageChart extends StatefulWidget { diff --git a/lib/common_widgets/jh_battery_widget.dart b/lib/widgets/jh_battery_widget.dart similarity index 100% rename from lib/common_widgets/jh_battery_widget.dart rename to lib/widgets/jh_battery_widget.dart diff --git a/lib/common_widgets/jh_custom_button.dart b/lib/widgets/jh_custom_button.dart similarity index 89% rename from lib/common_widgets/jh_custom_button.dart rename to lib/widgets/jh_custom_button.dart index 47dbd2c..1338f21 100644 --- a/lib/common_widgets/jh_custom_button.dart +++ b/lib/widgets/jh_custom_button.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/jh_size_config.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_size_config.dart'; import 'package:times_up_flutter/theme/theme.dart'; class JHCustomButton extends StatelessWidget { diff --git a/lib/common_widgets/jh_custom_raised_button.dart b/lib/widgets/jh_custom_raised_button.dart similarity index 100% rename from lib/common_widgets/jh_custom_raised_button.dart rename to lib/widgets/jh_custom_raised_button.dart diff --git a/lib/common_widgets/jh_display_text.dart b/lib/widgets/jh_display_text.dart similarity index 100% rename from lib/common_widgets/jh_display_text.dart rename to lib/widgets/jh_display_text.dart diff --git a/lib/common_widgets/jh_empty_content.dart b/lib/widgets/jh_empty_content.dart similarity index 93% rename from lib/common_widgets/jh_empty_content.dart rename to lib/widgets/jh_empty_content.dart index 78d1894..019478a 100644 --- a/lib/common_widgets/jh_empty_content.dart +++ b/lib/widgets/jh_empty_content.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; class JHEmptyContent extends StatelessWidget { const JHEmptyContent({ diff --git a/lib/common_widgets/jh_feature_widget.dart b/lib/widgets/jh_feature_widget.dart similarity index 96% rename from lib/common_widgets/jh_feature_widget.dart rename to lib/widgets/jh_feature_widget.dart index 5b42a4a..e6086bb 100644 --- a/lib/common_widgets/jh_feature_widget.dart +++ b/lib/widgets/jh_feature_widget.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; class JHFeatureWidget extends StatelessWidget { diff --git a/lib/common_widgets/jh_form_submit_button.dart b/lib/widgets/jh_form_submit_button.dart similarity index 79% rename from lib/common_widgets/jh_form_submit_button.dart rename to lib/widgets/jh_form_submit_button.dart index 30e3d3f..ef859ae 100644 --- a/lib/common_widgets/jh_form_submit_button.dart +++ b/lib/widgets/jh_form_submit_button.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_custom_raised_button.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_custom_raised_button.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; class FormSubmitButton extends JHCustomRaisedButton { FormSubmitButton({ diff --git a/lib/common_widgets/jh_header.dart b/lib/widgets/jh_header.dart similarity index 93% rename from lib/common_widgets/jh_header.dart rename to lib/widgets/jh_header.dart index d8d7718..a449328 100644 --- a/lib/common_widgets/jh_header.dart +++ b/lib/widgets/jh_header.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; class JHHeader extends StatelessWidget { diff --git a/lib/common_widgets/jh_header_widget.dart b/lib/widgets/jh_header_widget.dart similarity index 91% rename from lib/common_widgets/jh_header_widget.dart rename to lib/widgets/jh_header_widget.dart index 2b9f39d..edf013f 100644 --- a/lib/common_widgets/jh_header_widget.dart +++ b/lib/widgets/jh_header_widget.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; class HeaderWidget extends StatelessWidget { const HeaderWidget({ diff --git a/lib/common_widgets/jh_info_bottom_sheet.dart b/lib/widgets/jh_info_bottom_sheet.dart similarity index 92% rename from lib/common_widgets/jh_info_bottom_sheet.dart rename to lib/widgets/jh_info_bottom_sheet.dart index 2e6f278..f0a4519 100644 --- a/lib/common_widgets/jh_info_bottom_sheet.dart +++ b/lib/widgets/jh_info_bottom_sheet.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; class JHBottomSheet extends StatelessWidget { diff --git a/lib/common_widgets/jh_info_box.dart b/lib/widgets/jh_info_box.dart similarity index 95% rename from lib/common_widgets/jh_info_box.dart rename to lib/widgets/jh_info_box.dart index 2cf7175..00eb45d 100644 --- a/lib/common_widgets/jh_info_box.dart +++ b/lib/widgets/jh_info_box.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_size_config.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_size_config.dart'; typedef TriggerFunction = void Function()?; diff --git a/lib/common_widgets/jh_info_row_widget.dart b/lib/widgets/jh_info_row_widget.dart similarity index 86% rename from lib/common_widgets/jh_info_row_widget.dart rename to lib/widgets/jh_info_row_widget.dart index dee7844..bfd506c 100644 --- a/lib/common_widgets/jh_info_row_widget.dart +++ b/lib/widgets/jh_info_row_widget.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/jh_info_bottom_sheet.dart'; -import 'package:times_up_flutter/common_widgets/jh_info_box.dart'; -import 'package:times_up_flutter/common_widgets/show_bottom_sheet.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_info_bottom_sheet.dart'; +import 'package:times_up_flutter/widgets/jh_info_box.dart'; +import 'package:times_up_flutter/widgets/show_bottom_sheet.dart'; import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/utils/data.dart'; diff --git a/lib/common_widgets/jh_internet_connection_widget.dart b/lib/widgets/jh_internet_connection_widget.dart similarity index 100% rename from lib/common_widgets/jh_internet_connection_widget.dart rename to lib/widgets/jh_internet_connection_widget.dart diff --git a/lib/common_widgets/jh_loading_widget.dart b/lib/widgets/jh_loading_widget.dart similarity index 100% rename from lib/common_widgets/jh_loading_widget.dart rename to lib/widgets/jh_loading_widget.dart diff --git a/lib/common_widgets/jh_no_implementation.dart b/lib/widgets/jh_no_implementation.dart similarity index 92% rename from lib/common_widgets/jh_no_implementation.dart rename to lib/widgets/jh_no_implementation.dart index 27ab4c2..d49a73b 100644 --- a/lib/common_widgets/jh_no_implementation.dart +++ b/lib/widgets/jh_no_implementation.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; -import 'package:times_up_flutter/common_widgets/jh_custom_raised_button.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_custom_raised_button.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; class JHNoImplementationWidget extends StatelessWidget { diff --git a/lib/common_widgets/jh_pin_marker.dart b/lib/widgets/jh_pin_marker.dart similarity index 100% rename from lib/common_widgets/jh_pin_marker.dart rename to lib/widgets/jh_pin_marker.dart diff --git a/lib/common_widgets/jh_progress_bar.dart b/lib/widgets/jh_progress_bar.dart similarity index 100% rename from lib/common_widgets/jh_progress_bar.dart rename to lib/widgets/jh_progress_bar.dart diff --git a/lib/common_widgets/jh_size_config.dart b/lib/widgets/jh_size_config.dart similarity index 100% rename from lib/common_widgets/jh_size_config.dart rename to lib/widgets/jh_size_config.dart diff --git a/lib/common_widgets/jh_summary_tile.dart b/lib/widgets/jh_summary_tile.dart similarity index 86% rename from lib/common_widgets/jh_summary_tile.dart rename to lib/widgets/jh_summary_tile.dart index 89457af..74e9438 100644 --- a/lib/common_widgets/jh_summary_tile.dart +++ b/lib/widgets/jh_summary_tile.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; -import 'package:times_up_flutter/common_widgets/jh_progress_bar.dart'; -import 'package:times_up_flutter/common_widgets/jh_size_config.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_progress_bar.dart'; +import 'package:times_up_flutter/widgets/jh_size_config.dart'; class JHSummaryTile extends StatelessWidget { const JHSummaryTile({ diff --git a/lib/common_widgets/show_alert_dialog.dart b/lib/widgets/show_alert_dialog.dart similarity index 93% rename from lib/common_widgets/show_alert_dialog.dart rename to lib/widgets/show_alert_dialog.dart index ee461ee..14fb74e 100644 --- a/lib/common_widgets/show_alert_dialog.dart +++ b/lib/widgets/show_alert_dialog.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; -import 'package:times_up_flutter/common_widgets/jh_custom_raised_button.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_custom_raised_button.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; Future showAlertDialog( BuildContext context, { diff --git a/lib/common_widgets/show_bottom_sheet.dart b/lib/widgets/show_bottom_sheet.dart similarity index 100% rename from lib/common_widgets/show_bottom_sheet.dart rename to lib/widgets/show_bottom_sheet.dart diff --git a/lib/common_widgets/show_exeption_alert.dart b/lib/widgets/show_exeption_alert.dart similarity index 87% rename from lib/common_widgets/show_exeption_alert.dart rename to lib/widgets/show_exeption_alert.dart index 48bc36e..3725a80 100644 --- a/lib/common_widgets/show_exeption_alert.dart +++ b/lib/widgets/show_exeption_alert.dart @@ -1,6 +1,6 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; -import 'package:times_up_flutter/common_widgets/show_alert_dialog.dart'; +import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; Future showExceptionAlertDialog( BuildContext context, { diff --git a/lib/common_widgets/show_logger.dart b/lib/widgets/show_logger.dart similarity index 100% rename from lib/common_widgets/show_logger.dart rename to lib/widgets/show_logger.dart diff --git a/test/app/config/geo_full_test.dart b/test/app/config/geo_full_test.dart index e6306bf..4755466 100644 --- a/test/app/config/geo_full_test.dart +++ b/test/app/config/geo_full_test.dart @@ -3,7 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/app/config/geo_full.dart'; +import 'package:times_up_flutter/app/features/parent_side/map_page.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/services/geo_locator_service.dart'; import 'package:times_up_flutter/utils/constants.dart'; @@ -34,7 +34,7 @@ void main() { child: Provider( create: (_) => mockAuthBase, builder: (context, __) => MaterialApp( - home: GeoFull.create( + home: MapView.create( context, position: position, database: mockDatabase, @@ -60,7 +60,7 @@ void main() { child: Provider( create: (_) => mockAuthBase, builder: (context, __) => MaterialApp( - home: GeoFull.create( + home: MapView.create( context, position: position, database: mockDatabase, diff --git a/test/app/landing_page_test.dart b/test/app/landing_page_test.dart index 2daa583..20fdfbc 100644 --- a/test/app/landing_page_test.dart +++ b/test/app/landing_page_test.dart @@ -4,9 +4,9 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; -import 'package:times_up_flutter/app/pages/child_page.dart'; -import 'package:times_up_flutter/app/pages/parent_page.dart'; -import 'package:times_up_flutter/sign_in/sign_in_page.dart'; +import 'package:times_up_flutter/app/features/child_side/child_page.dart'; +import 'package:times_up_flutter/app/features/parent_side/parent_page.dart'; +import 'package:times_up_flutter/app/features/sign_in/sign_in_page.dart'; import '../helpers/test_helpers.dart'; import '../helpers/test_helpers.mocks.dart'; diff --git a/test/helpers/test_helpers.dart b/test/helpers/test_helpers.dart index 8d937f7..f6c9a53 100644 --- a/test/helpers/test_helpers.dart +++ b/test/helpers/test_helpers.dart @@ -3,14 +3,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/app/landing_page.dart'; +import 'package:times_up_flutter/app/features/landing_page.dart'; +import 'package:times_up_flutter/app/features/sign_in/email_sign_in_bloc.dart'; import 'package:times_up_flutter/services/app_usage_local_service.dart'; import 'package:times_up_flutter/services/app_usage_service.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/services/database.dart'; import 'package:times_up_flutter/services/geo_locator_service.dart'; import 'package:times_up_flutter/services/notification_service.dart'; -import 'package:times_up_flutter/sign_in/email_sign_in_bloc.dart'; import 'test_helpers.mocks.dart'; diff --git a/test/helpers/test_helpers.mocks.dart b/test/helpers/test_helpers.mocks.dart index b52f85a..0fa3c9f 100644 --- a/test/helpers/test_helpers.mocks.dart +++ b/test/helpers/test_helpers.mocks.dart @@ -17,6 +17,10 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart' import 'package:geolocator/geolocator.dart' as _i4; import 'package:installed_apps/app_info.dart' as _i21; import 'package:mockito/mockito.dart' as _i1; +import 'package:times_up_flutter/app/features/sign_in/email_sign_in_bloc.dart' + as _i17; +import 'package:times_up_flutter/app/features/sign_in/email_sign_in_model.dart' + as _i18; import 'package:times_up_flutter/models/child_model/child_model.dart' as _i3; import 'package:times_up_flutter/models/email_model.dart' as _i13; import 'package:times_up_flutter/models/notification_model/notification_model.dart' @@ -27,8 +31,6 @@ import 'package:times_up_flutter/services/auth.dart' as _i5; import 'package:times_up_flutter/services/database.dart' as _i10; import 'package:times_up_flutter/services/geo_locator_service.dart' as _i6; import 'package:times_up_flutter/services/notification_service.dart' as _i20; -import 'package:times_up_flutter/sign_in/email_sign_in_bloc.dart' as _i17; -import 'package:times_up_flutter/sign_in/email_sign_in_model.dart' as _i18; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values diff --git a/test/models/set_child_model_test.dart b/test/models/set_child_model_test.dart deleted file mode 100644 index 1750130..0000000 --- a/test/models/set_child_model_test.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:times_up_flutter/models/set_child_model.dart'; - -void main() { - test('SetChildModel Constructor', () { - // Test values - const name = 'John Doe'; - const email = 'john.doe@example.com'; - - // Create the SetChildModel instance - final setChildModel = SetChildModel( - name: name, - email: email, - ); - - // Verify the values - expect(setChildModel.name, name); - expect(setChildModel.email, email); - }); -} diff --git a/test/sign-in/email_sign_in_bloc_test.dart b/test/sign-in/email_sign_in_bloc_test.dart index 1781855..80249a8 100644 --- a/test/sign-in/email_sign_in_bloc_test.dart +++ b/test/sign-in/email_sign_in_bloc_test.dart @@ -1,8 +1,8 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; -import 'package:times_up_flutter/sign_in/email_sign_in_bloc.dart'; -import 'package:times_up_flutter/sign_in/email_sign_in_model.dart'; +import 'package:times_up_flutter/app/features/sign_in/email_sign_in_bloc.dart'; +import 'package:times_up_flutter/app/features/sign_in/email_sign_in_model.dart'; import '../helpers/test_helpers.mocks.dart'; diff --git a/test/sign-in/sign_in_manager_test.dart b/test/sign-in/sign_in_manager_test.dart index 67c2f5e..88452f9 100644 --- a/test/sign-in/sign_in_manager_test.dart +++ b/test/sign-in/sign_in_manager_test.dart @@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; -import 'package:times_up_flutter/sign_in/sign_in_manager.dart'; +import 'package:times_up_flutter/app/features/sign_in/sign_in_manager.dart'; import '../helpers/test_helpers.mocks.dart'; diff --git a/test/sign-in/sign_in_page_test.dart b/test/sign-in/sign_in_page_test.dart index 8eb1e30..98dca9e 100644 --- a/test/sign-in/sign_in_page_test.dart +++ b/test/sign-in/sign_in_page_test.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; +import 'package:times_up_flutter/app/features/sign_in/sign_in_button.dart'; +import 'package:times_up_flutter/app/features/sign_in/sign_in_page.dart'; import 'package:times_up_flutter/services/auth.dart'; -import 'package:times_up_flutter/sign_in/sign_in_button.dart'; -import 'package:times_up_flutter/sign_in/sign_in_page.dart'; import '../helpers/test_helpers.mocks.dart'; diff --git a/test/validators_test.dart b/test/validators_test.dart index a60e27b..450e605 100644 --- a/test/validators_test.dart +++ b/test/validators_test.dart @@ -1,31 +1,19 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:times_up_flutter/sign_in/validators.dart'; +import 'package:times_up_flutter/app/features/sign_in/validators.dart'; void main() { test('non empty string ', () { final validator = NonEmptyStringValidator(); - - ///here we pass a string [test] to check if the method isValid will - /// return true - /// expect(validator.isValid('test'), true); }); test('empty string ', () { final validator = NonEmptyStringValidator(); - - ///here we pass a string [test] to check if the method isValid will - ///return false - /// when the string is empty expect(validator.isValid(''), false); }); test('null string ', () { final validator = NonEmptyStringValidator(); - - ///here we pass a string [test] to check if the method isValid will - ///return null - /// when the string is empty expect(validator.isValid(null), false); }); } diff --git a/test/common_widgets/auto_size_text_test.dart b/test/widgets/auto_size_text_test.dart similarity index 91% rename from test/common_widgets/auto_size_text_test.dart rename to test/widgets/auto_size_text_test.dart index 0b94b2c..44b525b 100644 --- a/test/common_widgets/auto_size_text_test.dart +++ b/test/widgets/auto_size_text_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:times_up_flutter/common_widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; import '../helpers/test_helpers.dart'; diff --git a/test/common_widgets/bar_chart_test.dart b/test/widgets/bar_chart_test.dart similarity index 100% rename from test/common_widgets/bar_chart_test.dart rename to test/widgets/bar_chart_test.dart diff --git a/test/common_widgets/custom_raised_button_test.dart b/test/widgets/custom_raised_button_test.dart similarity index 94% rename from test/common_widgets/custom_raised_button_test.dart rename to test/widgets/custom_raised_button_test.dart index ac6f9cc..fbadddc 100644 --- a/test/common_widgets/custom_raised_button_test.dart +++ b/test/widgets/custom_raised_button_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:times_up_flutter/common_widgets/jh_custom_raised_button.dart'; +import 'package:times_up_flutter/widgets/jh_custom_raised_button.dart'; void main() { /// This syntax is used to test widgets diff --git a/test/common_widgets/empty_content_test.dart b/test/widgets/empty_content_test.dart similarity index 88% rename from test/common_widgets/empty_content_test.dart rename to test/widgets/empty_content_test.dart index b2dfcbf..39201e8 100644 --- a/test/common_widgets/empty_content_test.dart +++ b/test/widgets/empty_content_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:times_up_flutter/common_widgets/jh_empty_content.dart'; +import 'package:times_up_flutter/widgets/jh_empty_content.dart'; import '../helpers/test_helpers.dart'; diff --git a/test/common_widgets/feature_widget_test.dart b/test/widgets/feature_widget_test.dart similarity index 100% rename from test/common_widgets/feature_widget_test.dart rename to test/widgets/feature_widget_test.dart diff --git a/test/common_widgets/loading_map_test.dart b/test/widgets/loading_map_test.dart similarity index 100% rename from test/common_widgets/loading_map_test.dart rename to test/widgets/loading_map_test.dart diff --git a/test/common_widgets/show_alert_dialog.dart b/test/widgets/show_alert_dialog.dart similarity index 100% rename from test/common_widgets/show_alert_dialog.dart rename to test/widgets/show_alert_dialog.dart From 07ccef409f8b9e4083d5e17735323d60cac04841 Mon Sep 17 00:00:00 2001 From: jordyhers Date: Fri, 20 Oct 2023 09:32:11 +0200 Subject: [PATCH 04/23] fix: completely revamp app look --- .idea/libraries/Flutter_Plugins.xml | 1 + android/app/src/main/AndroidManifest.xml | 15 +- android/build.gradle | 3 + lib/app/app.dart | 7 +- lib/app/config/android_config.dart | 36 +++ lib/app/features/child_side/child_page.dart | 20 +- .../features/parent_side/app_list_page.dart | 87 ++++++ .../parent_side/child_details_page.dart | 284 ++++++++--------- .../features/parent_side/edit_child_page.dart | 48 +-- .../parent_side/notification_page.dart | 103 ++++--- lib/app/features/parent_side/parent_page.dart | 259 +++++++--------- .../features/parent_side/setting_page.dart | 203 ++++++++---- lib/app/helpers/parsing_extension.dart | 16 + lib/app/lifecycle/life_cycle.dart | 43 ++- lib/main_development.dart | 8 +- .../notification_model.dart | 1 + .../notification_model.freezed.dart | 44 ++- .../notification_model.g.dart | 4 + lib/services/database.dart | 14 +- lib/services/firestore_service.dart | 12 +- lib/theme/theme.dart | 1 + lib/widgets/jh_bar_chart.dart | 102 +------ lib/widgets/jh_custom_button.dart | 15 +- lib/widgets/jh_display_text.dart | 3 + lib/widgets/jh_info_row_widget.dart | 5 +- lib/widgets/jh_line_chart.dart | 289 ++++++++++++++++++ lib/widgets/jh_no_implementation.dart | 36 ++- lib/widgets/jh_shimmer_map.dart | 19 ++ pubspec.lock | 56 ++-- pubspec.yaml | 2 + test/helpers/test_helpers.mocks.dart | 18 +- test/services/firestore_service_test.dart | 2 +- 32 files changed, 1159 insertions(+), 597 deletions(-) create mode 100644 lib/app/config/android_config.dart create mode 100644 lib/app/features/parent_side/app_list_page.dart create mode 100644 lib/widgets/jh_line_chart.dart create mode 100644 lib/widgets/jh_shimmer_map.dart diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 3cbabd7..fcc3018 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -58,6 +58,7 @@ + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 2070d06..90183ad 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,15 +7,14 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> - - - + + + + + + createState() => _TimesUpAppState(); -} - -class _TimesUpAppState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([ diff --git a/lib/app/config/android_config.dart b/lib/app/config/android_config.dart new file mode 100644 index 0000000..62507b9 --- /dev/null +++ b/lib/app/config/android_config.dart @@ -0,0 +1,36 @@ +import 'package:background_fetch/background_fetch.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; + +@pragma('vm:entry-point') +Future backgroundFetchHeadlessTask(HeadlessTask task) async { + final taskId = task.taskId; + final isTimeout = task.timeout; + + JHLogger.$.e('[BackgroundFetch] Headless event received.'); + + if (isTimeout) { + JHLogger.$.e('[BackgroundFetch] Headless task timed-out: $taskId'); + BackgroundFetch.finish(taskId); + return; + } +} + +Future configureBackgroundFetch() async { + await BackgroundFetch.configure( + BackgroundFetchConfig( + minimumFetchInterval: 1, + stopOnTerminate: false, + enableHeadless: true, + requiresBatteryNotLow: false, + requiresCharging: false, + requiresStorageNotLow: false, + requiresDeviceIdle: false, + requiredNetworkType: NetworkType.NONE, + ), + backgroundFetchHeadlessTask, + ).then((int status) { + JHLogger.$.e('[BackgroundFetch] Headless task timed-out- $status'); + }).catchError((e) { + JHLogger.$.d("[BackgroundFetch] configure ERROR: $e"); + }); +} diff --git a/lib/app/features/child_side/child_page.dart b/lib/app/features/child_side/child_page.dart index 21954cf..3e06c4e 100644 --- a/lib/app/features/child_side/child_page.dart +++ b/lib/app/features/child_side/child_page.dart @@ -19,6 +19,7 @@ import 'package:times_up_flutter/services/geo_locator_service.dart'; import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/widgets/jh_empty_content.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; class ChildPage extends StatefulWidget { const ChildPage({ @@ -66,11 +67,24 @@ class _ChildPageState extends State with WidgetsBindingObserver { Navigator.pop(context); } + @override + void initState() { + super.initState(); + + WidgetsBinding.instance.addObserver(this); + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + @override void didChangeAppLifecycleState(AppLifecycleState state) { - Timer.periodic(const Duration(minutes: 5), (timer) { - widget.database - ?.liveUpdateChild(widget.child!, timer.tick, widget.appUsage); + Timer.periodic(const Duration(seconds: 5), (timer) async { + await widget.database?.liveUpdateChild(widget.child!, widget.appUsage); + JHLogger.$.d('${timer.tick} - $state'); }); super.didChangeAppLifecycleState(state); } diff --git a/lib/app/features/parent_side/app_list_page.dart b/lib/app/features/parent_side/app_list_page.dart new file mode 100644 index 0000000..f6f16ce --- /dev/null +++ b/lib/app/features/parent_side/app_list_page.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:times_up_flutter/app/helpers/parsing_extension.dart'; +import 'package:times_up_flutter/models/child_model/child_model.dart'; + +class AppListPage extends StatelessWidget { + const AppListPage({ + required this.childModel, + Key? key, + }) : super(key: key); + + final ChildModel childModel; + + static Future show(BuildContext context, ChildModel model) async { + await Navigator.of(context).push( + PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) { + return AppListPage(childModel: model); + }, + transitionsBuilder: (context, animation, secondaryAnimation, child) { + const begin = Offset(1, 0); + const end = Offset.zero; + const curve = Curves.easeInOut; + final tween = + Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + final offsetAnimation = animation.drive(tween); + return SlideTransition( + position: offsetAnimation, + child: child, + ); + }, + transitionDuration: const Duration(milliseconds: 400), + ), + ); + } + + @override + Widget build(BuildContext context) { + final themeData = Theme.of(context); + + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.chevron_left), + onPressed: () => Navigator.of(context).pop(), + ), + elevation: 0, + backgroundColor: themeData.scaffoldBackgroundColor, + ), + body: ListView.builder( + physics: const BouncingScrollPhysics( + decelerationRate: ScrollDecelerationRate.fast), + itemCount: childModel.appsUsageModel.length, + itemBuilder: (context, index) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: childModel.appsUsageModel[index].appIcon != null + ? Image.memory( + childModel.appsUsageModel[index].appIcon!, + height: 35, + ) + : const Icon(Icons.android), + title: Text( + childModel.appsUsageModel[index].appName, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: themeData.dividerColor, + ), + ), + trailing: Text( + childModel.appsUsageModel[index].usage.toString().t(), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: themeData.dividerColor, + ), + ), + ), + ], + ); + }, + ), + ); + } +} diff --git a/lib/app/features/parent_side/child_details_page.dart b/lib/app/features/parent_side/child_details_page.dart index 71ac156..93ef68e 100644 --- a/lib/app/features/parent_side/child_details_page.dart +++ b/lib/app/features/parent_side/child_details_page.dart @@ -9,23 +9,23 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:times_up_flutter/app/features/parent_side/app_list_page.dart'; import 'package:times_up_flutter/app/helpers/parsing_extension.dart'; -import 'package:times_up_flutter/widgets/jh_bar_chart.dart'; +import 'package:times_up_flutter/l10n/l10n.dart'; +import 'package:times_up_flutter/models/child_model/child_model.dart'; +import 'package:times_up_flutter/models/notification_model/notification_model.dart'; +import 'package:times_up_flutter/services/database.dart'; +import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/widgets/jh_battery_widget.dart'; import 'package:times_up_flutter/widgets/jh_custom_button.dart'; import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/widgets/jh_empty_content.dart'; -import 'package:times_up_flutter/widgets/jh_feature_widget.dart'; import 'package:times_up_flutter/widgets/jh_header_widget.dart'; +import 'package:times_up_flutter/widgets/jh_line_chart.dart'; import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; import 'package:times_up_flutter/widgets/show_bottom_sheet.dart'; import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; import 'package:times_up_flutter/widgets/show_logger.dart'; -import 'package:times_up_flutter/l10n/l10n.dart'; -import 'package:times_up_flutter/models/child_model/child_model.dart'; -import 'package:times_up_flutter/models/notification_model/notification_model.dart'; -import 'package:times_up_flutter/services/database.dart'; -import 'package:times_up_flutter/theme/theme.dart'; class ChildDetailsPage extends StatefulWidget { const ChildDetailsPage({ @@ -39,10 +39,25 @@ class ChildDetailsPage extends StatefulWidget { static Future show(BuildContext context, ChildModel model) async { final database = Provider.of(context, listen: false); + await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => - ChildDetailsPage(database: database, childModel: model), + PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) { + return ChildDetailsPage(database: database, childModel: model); + }, + transitionsBuilder: (context, animation, secondaryAnimation, child) { + const begin = Offset(1, 0); + const end = Offset.zero; + const curve = Curves.easeInOut; + final tween = + Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + final offsetAnimation = animation.drive(tween); + return SlideTransition( + position: offsetAnimation, + child: child, + ); + }, + transitionDuration: const Duration(milliseconds: 400), ), ); } @@ -116,9 +131,46 @@ class _ChildDetailsPageState extends State if (model.image != null) Row( children: [ - ClipOval( - child: Image.network(model.image!), - ).p4, + GestureDetector( + onTap: () => showCustomBottomSheet( + context, + animationController: _animationController, + child: Container( + decoration: BoxDecoration( + color: themeData.scaffoldBackgroundColor, + ), + height: 200, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Spacer(), + JHCustomButton( + title: ' Bed Time', + backgroundColor: Colors.indigo, + onPress: () async => _sendNotification( + context, + model, + 'Hey Go to bed Now', + ), + ), + JHCustomButton( + title: 'Homework Time', + backgroundColor: CustomColors.indigoLight, + onPress: () async => _sendNotification( + context, + model, + 'Homework Time', + ), + ), + const Spacer(), + ], + ), + ), + ), + child: ClipOval( + child: Image.network(model.image!), + ).p4, + ), ], ) else @@ -136,13 +188,6 @@ class _ChildDetailsPageState extends State iconTheme: const IconThemeData(color: Colors.red), backgroundColor: themeData.scaffoldBackgroundColor, expandedHeight: 50, - shape: ContinuousRectangleBorder( - side: BorderSide( - color: !value - ? themeData.scaffoldBackgroundColor - : CustomColors.indigoLight.withOpacity(0.5), - ), - ), pinned: true, floating: true, ), @@ -214,77 +259,19 @@ class _ChildDetailsPageState extends State margin: const EdgeInsets.symmetric(horizontal: 8), height: 205, width: double.infinity, - child: model.appsUsageModel.isNotEmpty - ? JHAppUsageChart( - isEmpty: false, - name: model.name, - ) - : JHAppUsageChart( - isEmpty: true, - name: model.name, - ), + child: JHLineChart(model: model), ), ], ).vTopP(20), - HeaderWidget( - title: AppLocalizations.of(context) - .sendNotificationToYourChildDevice, - subtitle: 'Push the button ', - ), - GestureDetector( - onTap: () => showCustomBottomSheet( - context, - animationController: _animationController, - child: Container( - decoration: BoxDecoration( - color: themeData.scaffoldBackgroundColor, - ), - height: 200, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Spacer(), - JHCustomButton( - title: ' Bed Time', - backgroundColor: Colors.indigo, - onPress: () async => _sendNotification( - context, - model, - 'Hey Go to bed Now', - ), - ), - JHCustomButton( - title: 'Homework Time', - backgroundColor: CustomColors.indigoLight, - onPress: () async => _sendNotification( - context, - model, - 'Homework Time', - ), - ), - const Spacer(), - ], - ), - ), - ), - child: const JHFeatureWidget( - title: 'Send Notification', - icon: Icons.wifi_tethering_error_sharp, - ), - ), - _AppUsedList( - model: model, - ), + _AppUsedList(model: model).vP16, JHCustomButton( title: 'Delete Child', - backgroundColor: Colors.transparent, - borderColor: Colors.red, - textColor: Colors.red, + backgroundColor: Colors.red, onPress: () async => _confirmDelete( context, widget.childModel, ), - ).vTopP(50), + ).vTopP(70), ]), ), ], @@ -327,9 +314,11 @@ class _ChildDetailsPageState extends State title: ' Hey ${model.name}', body: 'Here is a new message', message: content, + timeStamp: DateTime.now(), ), model, ); + Navigator.of(context).pop(); if (!mounted) return; await showAlertDialog( context, @@ -358,65 +347,80 @@ class _AppUsedList extends StatelessWidget { @override Widget build(BuildContext context) { final themeData = Theme.of(context); - return SingleChildScrollView( - child: ScrollConfiguration( - behavior: const ScrollBehavior().copyWith(overscroll: false), - child: Column( - children: [ - if (model.appsUsageModel.isNotEmpty) - const HeaderWidget( - title: 'Summary of used apps', - subtitle: 'Click for more details', - ) - else - const SizedBox.shrink().vP16, - if (model.appsUsageModel.isNotEmpty) - ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: model.appsUsageModel.length, - itemBuilder: (context, index) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - leading: model.appsUsageModel[index].appIcon != null - ? Image.memory( - model.appsUsageModel[index].appIcon!, - height: 35, - ) - : const Icon(Icons.android), - title: Text( - model.appsUsageModel[index].appName, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - color: themeData.dividerColor, - ), - ), - trailing: Text( - model.appsUsageModel[index].usage.toString().t(), - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: themeData.dividerColor, - ), - ), - ), - ], - ); - }, - ) - else - const JHEmptyContent( - message: 'Seems like you have not set up the child device \n', - title: 'Set up the child device', - fontSizeMessage: 8, - fontSizeTitle: 12, + return Column( + children: [ + if (model.appsUsageModel.isNotEmpty) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const SizedBox( + width: 300, + child: HeaderWidget( + title: 'Summary of used apps', + subtitle: 'Click for more details', + ), ), - ], - ), - ), + TextButton( + child: Text( + 'See all', + style: TextStyle( + decoration: TextDecoration.underline, + color: CustomColors.indigoLight, + fontSize: 13, + ), + ), + onPressed: () => AppListPage.show(context, model), + ), + ], + ) + else + const SizedBox.shrink().vP16, + if (model.appsUsageModel.isNotEmpty) + ListView.builder( + padding: EdgeInsets.zero, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: (model.appsUsageModel.length * 0.20).toInt(), + itemBuilder: (context, index) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: model.appsUsageModel[index].appIcon != null + ? Image.memory( + model.appsUsageModel[index].appIcon!, + height: 35, + ) + : const Icon(Icons.android), + title: Text( + model.appsUsageModel[index].appName, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: themeData.dividerColor, + ), + ), + trailing: Text( + model.appsUsageModel[index].usage.toString().t(), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: themeData.dividerColor, + ), + ), + ), + ], + ); + }, + ) + else + const JHEmptyContent( + message: 'Seems like you have not set up the child device \n', + title: 'Set up the child device', + fontSizeMessage: 8, + fontSizeTitle: 12, + ), + ], ); } } diff --git a/lib/app/features/parent_side/edit_child_page.dart b/lib/app/features/parent_side/edit_child_page.dart index 126fdd5..729e501 100644 --- a/lib/app/features/parent_side/edit_child_page.dart +++ b/lib/app/features/parent_side/edit_child_page.dart @@ -6,14 +6,14 @@ import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:path/path.dart' as path; +import 'package:times_up_flutter/models/child_model/child_model.dart'; +import 'package:times_up_flutter/services/database.dart'; +import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/widgets/jh_custom_raised_button.dart'; import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; import 'package:times_up_flutter/widgets/show_logger.dart'; -import 'package:times_up_flutter/models/child_model/child_model.dart'; -import 'package:times_up_flutter/services/database.dart'; -import 'package:times_up_flutter/theme/theme.dart'; import 'package:uuid/uuid.dart'; enum AppState { loading, complete } @@ -128,7 +128,7 @@ class _EditChildPageState extends State { await showAlertDialog( context, title: ' Name already used', - content: 'Please choose a different job name', + content: 'Please choose a different child name', defaultActionText: 'OK', ); } @@ -162,6 +162,18 @@ class _EditChildPageState extends State { @override Widget build(BuildContext context) { return Scaffold( + floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, + floatingActionButton: JHCustomRaisedButton( + width: MediaQuery.of(context).size.width * 0.80, + onPressed: () async => _submit(_imageFile), + color: CustomColors.indigoDark, + child: JHDisplayText( + text: 'Save', + style: TextStyle( + color: Theme.of(context).scaffoldBackgroundColor, + ), + ), + ).vP16, backgroundColor: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.9), appBar: AppBar( @@ -183,15 +195,14 @@ class _EditChildPageState extends State { Widget _buildContents() { return !isSavedPressed - ? SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(16), - child: Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: _buildForm(), - ), - ), + ? SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _buildForm().p(32), + const Spacer(), + ], ), ) : const Center(child: CircularProgressIndicator()); @@ -236,7 +247,7 @@ class _EditChildPageState extends State { ), onPressed: _getLocalImage, child: const JHDisplayText( - text: 'Upload', + text: 'Import ', style: TextStyle(color: Colors.white), ), ), @@ -258,15 +269,6 @@ class _EditChildPageState extends State { enabled: appState == AppState.complete || false, onSaved: (value) => _email = value, ), - JHCustomRaisedButton( - width: 200, - onPressed: () async => _submit(_imageFile), - color: Colors.indigo, - child: const JHDisplayText( - text: 'Save', - style: TextStyle(color: Colors.white), - ), - ).vTopP(24) ]; } diff --git a/lib/app/features/parent_side/notification_page.dart b/lib/app/features/parent_side/notification_page.dart index dca18ba..99b5282 100644 --- a/lib/app/features/parent_side/notification_page.dart +++ b/lib/app/features/parent_side/notification_page.dart @@ -4,14 +4,15 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/widgets/jh_display_text.dart'; -import 'package:times_up_flutter/widgets/jh_loading_widget.dart'; -import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; +import 'package:times_up_flutter/app/helpers/parsing_extension.dart'; import 'package:times_up_flutter/models/notification_model/notification_model.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/services/database.dart'; import 'package:times_up_flutter/services/notification_service.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_loading_widget.dart'; +import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; enum AppState { loaded, empty } @@ -63,34 +64,22 @@ class _NotificationPageState extends State { void initState() { super.initState(); widget.auth.setToken(); - widget.notification?.configureFirebaseMessaging(); } @override Widget build(BuildContext context) { + final color = Theme.of(context).brightness == Brightness.dark + ? Colors.white + : CustomColors.indigoDark; return NestedScrollView( headerSliverBuilder: (BuildContext context, value) { return [ SliverAppBar( elevation: 0.5, shadowColor: CustomColors.indigoLight, - title: const JHDisplayText( - text: 'Notifications', - style: TextStyle( - color: Colors.indigo, - fontWeight: FontWeight.w900, - ), - ), iconTheme: const IconThemeData(color: Colors.red), backgroundColor: Theme.of(context).scaffoldBackgroundColor, expandedHeight: 50, - shape: ContinuousRectangleBorder( - side: BorderSide( - color: !value - ? Theme.of(context).scaffoldBackgroundColor - : CustomColors.indigoLight.withOpacity(0.5), - ), - ), pinned: true, floating: true, ) @@ -100,6 +89,28 @@ class _NotificationPageState extends State { behavior: const ScrollBehavior().copyWith(overscroll: false), child: CustomScrollView( slivers: [ + SliverToBoxAdapter( + child: JHDisplayText( + text: 'Notifications', + style: TextStyle( + color: color, + fontWeight: FontWeight.w700, + ), + fontSize: 32, + maxFontSize: 34, + ).hP16, + ), + SliverToBoxAdapter( + child: JHDisplayText( + text: 'slide from right to left to dismiss', + style: TextStyle( + color: Colors.grey.withOpacity(0.5), + fontWeight: FontWeight.w400, + ), + fontSize: 12, + maxFontSize: 14, + ).hP16, + ), SliverList( delegate: SliverChildListDelegate([ SingleChildScrollView( @@ -114,9 +125,15 @@ class _NotificationPageState extends State { } Widget _buildStreamNotification(BuildContext context) { + final color = Theme.of(context).brightness == Brightness.dark + ? Colors.white + : CustomColors.indigoDark; return StreamBuilder>( stream: widget.database?.notificationStream(), builder: (BuildContext context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const SizedBox.shrink(); + } if (snapshot.hasData) { final data = snapshot.data; @@ -152,28 +169,34 @@ class _NotificationPageState extends State { }); }, direction: DismissDirection.endToStart, - child: Card( - color: CustomColors.indigoLight, - child: Padding( - padding: const EdgeInsets.all(8), - child: ListTile( - title: JHDisplayText( - text: data[index].title ?? 'No title available', - style: const TextStyle( - fontWeight: FontWeight.w600, - color: Colors.white, - fontSize: 16, - ), - ), - trailing: JHDisplayText( - text: - data[index].message ?? 'No message available', - style: const TextStyle( - fontWeight: FontWeight.w600, - color: Colors.white, - fontSize: 16, - ), - ), + child: ListTile( + contentPadding: + const EdgeInsets.symmetric(horizontal: 10), + subtitle: JHDisplayText( + textAlign: TextAlign.start, + text: convertToFormattedString( + data[index].timeStamp.toString(), + ), + style: const TextStyle( + fontWeight: FontWeight.w400, + color: Colors.grey, + fontSize: 14, + ), + ), + title: JHDisplayText( + text: data[index].title ?? 'No title available', + style: TextStyle( + fontWeight: FontWeight.w600, + color: color, + fontSize: 16, + ), + ), + trailing: JHDisplayText( + text: data[index].message ?? 'No message available', + style: TextStyle( + fontWeight: FontWeight.w600, + color: color, + fontSize: 16, ), ), ), diff --git a/lib/app/features/parent_side/parent_page.dart b/lib/app/features/parent_side/parent_page.dart index 1b2136c..60eb362 100644 --- a/lib/app/features/parent_side/parent_page.dart +++ b/lib/app/features/parent_side/parent_page.dart @@ -6,6 +6,7 @@ import 'package:geolocator/geolocator.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; import 'package:provider/provider.dart'; import 'package:showcaseview/showcaseview.dart'; +import 'package:times_up_flutter/app/features/parent_side/child_details_page.dart'; import 'package:times_up_flutter/app/features/parent_side/edit_child_page.dart'; import 'package:times_up_flutter/app/features/parent_side/map_page.dart'; import 'package:times_up_flutter/app/features/parent_side/notification_page.dart'; @@ -28,11 +29,9 @@ import 'package:times_up_flutter/widgets/jh_empty_content.dart'; import 'package:times_up_flutter/widgets/jh_header.dart'; import 'package:times_up_flutter/widgets/jh_header_widget.dart'; import 'package:times_up_flutter/widgets/jh_info_row_widget.dart'; -import 'package:times_up_flutter/widgets/jh_loading_widget.dart'; +import 'package:times_up_flutter/widgets/jh_shimmer_map.dart'; import 'package:times_up_flutter/widgets/jh_summary_tile.dart'; - -import '../../../widgets/show_logger.dart'; -import 'child_details_page.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; typedef ValueList = List>; @@ -86,6 +85,7 @@ class _ParentPageState extends State _getAverageUsage(); _getAllChildLocations(); _setShowCaseView(); + _scrollController = ScrollController(); _animationController = AnimationController( vsync: this, @@ -137,152 +137,127 @@ class _ParentPageState extends State Widget _buildDashboard(Database database, AuthBase auth) { final themeData = Theme.of(context); - return StreamBuilder>( - stream: database.childrenStream(), - builder: (context, AsyncSnapshot> snapshot) { - final data = snapshot.data; - if (snapshot.connectionState == ConnectionState.waiting) { - return const LoadingWidget(); - } else if (snapshot.hasError) { - return const JHEmptyContent( - title: 'Error Occurred !', - ); - } else { - return NestedScrollView( - controller: _scrollController, - headerSliverBuilder: (context, value) { - return [ - SliverAppBar( - elevation: 0.5, - shadowColor: CustomColors.indigoLight, - toolbarHeight: value ? 75 : 90, - flexibleSpace: - !value ? const JHHeader().hP16 : const SizedBox.shrink(), - backgroundColor: themeData.scaffoldBackgroundColor, - expandedHeight: !value ? 120 : 100, - shape: ContinuousRectangleBorder( - side: BorderSide( - color: !value - ? themeData.scaffoldBackgroundColor - : CustomColors.indigoDark.withOpacity(0.5), + return NestedScrollView( + controller: _scrollController, + headerSliverBuilder: (context, value) { + return [ + SliverAppBar( + elevation: 0.5, + shadowColor: CustomColors.indigoLight, + toolbarHeight: value ? 75 : 90, + flexibleSpace: + !value ? const JHHeader().hP16 : const SizedBox.shrink(), + backgroundColor: themeData.scaffoldBackgroundColor, + expandedHeight: !value ? 120 : 100, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (!value) + const SizedBox.shrink() + else + JHDisplayText( + text: AppLocalizations.of(context).welcome, + style: const TextStyle( + color: Colors.indigo, + fontWeight: FontWeight.w900, ), ), - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (!value) - const SizedBox.shrink() - else - JHDisplayText( - text: AppLocalizations.of(context).welcome, - style: const TextStyle( - color: Colors.indigo, - fontWeight: FontWeight.w900, - ), - ), - GestureDetector( - onTap: () => SettingsPage.show(context, auth), - child: Showcase( - key: _settingsKey, - textColor: Colors.indigo, - description: AppLocalizations.of(context) - .changeTheSettingsHere, - child: const CircleAvatar( - child: Icon(Icons.person), - ), - ), - ), - ], - ), - pinned: true, - floating: true, - ), - ]; - }, - body: RefreshIndicator( - triggerMode: RefreshIndicatorTriggerMode.anywhere, - color: Theme.of(context).scaffoldBackgroundColor, - backgroundColor: Colors.indigo, - onRefresh: () => Future.wait([ - _getAverageUsage(), - _getAllChildLocations(), - _loadingTime(), - ]), - child: Scaffold( - floatingActionButton: Showcase( - key: _addKey, + Showcase( + key: _settingsKey, textColor: Colors.indigo, - description: AppLocalizations.of(context).addNewChildHere, - child: FloatingActionButton( - onPressed: () => EditChildPage.show( - context, - database: Provider.of(context, listen: false), - ), - backgroundColor: CustomColors.indigoLight, - child: const Icon(Icons.add), + description: + AppLocalizations.of(context).changeTheSettingsHere, + child: IconButton.outlined( + onPressed: () => SettingsPage.show(context, auth), + icon: const Icon(Icons.settings), + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : CustomColors.indigoPrimary, ), ), - body: ScrollConfiguration( - behavior: const ScrollBehavior().copyWith(overscroll: false), - child: CustomScrollView( - slivers: [ - SliverList( - delegate: SliverChildListDelegate( - [ - HeaderWidget( - title: 'My Children', - subtitle: - 'Choose child to get more info - scroll ' - 'right', - trailing: IconButton( - icon: const Icon(Icons.info_outline), - onPressed: _startShowCase, - ), - ).hP4, - _buildChildrenList(database), - const HeaderWidget( - title: 'Get to see our child live app usage', - subtitle: 'Click on it to have the full report', - ).hP4, - JHSummaryTile( - title: formatDateTime(DateTime.now()), - time: data != null && data.isNotEmpty - ? _averageUsage.toString().t() - : '0h 0m', - progressValue: data != null && data.isNotEmpty - ? calculatePercentage(_averageUsage) - : 0, - ).vP4, - const HeaderWidget( - title: 'Information Section', - subtitle: 'Get tips on how to use the app.', - ).hP4, - JHInfoRow( - animationController: _animationController, - icon_1: Icons.auto_graph_outlined, - icon_2: Icons.message_outlined, - dataOne: MockData.text_1, - dataTwo: MockData.text_2, - ).p8, - JHInfoRow( - animationController: _animationController, - icon_1: Icons.lightbulb_rounded, - icon_2: Icons.volume_up_outlined, - dataOne: MockData.text_3, - dataTwo: MockData.text_4, - ).p8, - const SizedBox(height: 150), - ], + ], + ), + pinned: true, + floating: true, + ), + ]; + }, + body: RefreshIndicator( + triggerMode: RefreshIndicatorTriggerMode.anywhere, + color: Theme.of(context).scaffoldBackgroundColor, + backgroundColor: Colors.indigo, + onRefresh: () => Future.wait([ + _getAverageUsage(), + _getAllChildLocations(), + _loadingTime(), + ]), + child: Scaffold( + floatingActionButton: Showcase( + key: _addKey, + textColor: Colors.indigo, + description: AppLocalizations.of(context).addNewChildHere, + child: FloatingActionButton( + onPressed: () => EditChildPage.show( + context, + database: database, + ), + backgroundColor: CustomColors.greenPrimary, + child: const Icon(Icons.add), + ), + ), + body: ScrollConfiguration( + behavior: const ScrollBehavior().copyWith(overscroll: false), + child: CustomScrollView( + slivers: [ + SliverList( + delegate: SliverChildListDelegate( + [ + HeaderWidget( + title: 'My Children', + subtitle: 'Choose child to get more info - scroll ' + 'right', + trailing: IconButton( + icon: const Icon(Icons.info_outline), + onPressed: _startShowCase, ), - ), + ).hP4, + _buildChildrenList(database), + const HeaderWidget( + title: 'Get to see our child live app usage', + subtitle: 'Click on it to have the full report', + ).hP4, + JHSummaryTile( + title: formatDateTime(DateTime.now()), + time: _averageUsage.toString().t(), + progressValue: calculatePercentage(_averageUsage), + ).vP4, + const HeaderWidget( + title: 'Information Section', + subtitle: 'Get tips on how to use the app.', + ).hP4, + JHInfoRow( + animationController: _animationController, + icon_1: Icons.auto_graph_outlined, + icon_2: Icons.message_outlined, + dataOne: MockData.text_1, + dataTwo: MockData.text_2, + ).p8, + JHInfoRow( + animationController: _animationController, + icon_1: Icons.lightbulb_rounded, + icon_2: Icons.volume_up_outlined, + dataOne: MockData.text_3, + dataTwo: MockData.text_4, + ).p8, + const SizedBox(height: 150), ], ), ), - ), + ], ), - ); - } - }, + ), + ), + ), ); } @@ -318,7 +293,7 @@ class _ParentPageState extends State child: Icon(Icons.info_outline_rounded), ); } - } else if (snapshot.hasData) { + } else if (snapshot.hasError) { JHLogger.$.e(snapshot.error); return const Center( child: Row( @@ -361,7 +336,7 @@ class _ParentPageState extends State auth: auth, locations: values, ) - : const LoadingWidget(); + : const ShimmerMap(); }, ); } diff --git a/lib/app/features/parent_side/setting_page.dart b/lib/app/features/parent_side/setting_page.dart index fe9ff79..eb0e021 100644 --- a/lib/app/features/parent_side/setting_page.dart +++ b/lib/app/features/parent_side/setting_page.dart @@ -3,14 +3,15 @@ import 'package:flutter/material.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; import 'package:provider/provider.dart'; -import 'package:times_up_flutter/widgets/jh_display_text.dart'; -import 'package:times_up_flutter/widgets/jh_no_implementation.dart'; -import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; -import 'package:times_up_flutter/widgets/show_logger.dart'; import 'package:times_up_flutter/services/app_info_service.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/theme/theme_notifier.dart'; +import 'package:times_up_flutter/widgets/jh_custom_button.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; +import 'package:times_up_flutter/widgets/jh_no_implementation.dart'; +import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; class SettingsPage extends StatelessWidget { const SettingsPage({ @@ -73,6 +74,17 @@ class SettingsPage extends StatelessWidget { child: ListView( physics: const BouncingScrollPhysics(), children: [ + JHDisplayText( + text: 'Profile', + style: TextStyle( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : CustomColors.indigoDark, + fontWeight: FontWeight.w700, + ), + fontSize: 27, + maxFontSize: 34, + ).hP16, ProfileListItem( icon: LineAwesomeIcons.history, onPressed: () => showDialog( @@ -80,7 +92,7 @@ class SettingsPage extends StatelessWidget { builder: (_) => const JHNoImplementationWidget(), ), text: 'Update profile', - ), + ).vTopP(12), ProfileListItem( icon: LineAwesomeIcons.language, onPressed: () => showDialog( @@ -89,6 +101,14 @@ class SettingsPage extends StatelessWidget { ), text: 'Change language', ), + ProfileListItem( + icon: LineAwesomeIcons.bell, + onPressed: () => showDialog( + context: context, + builder: (_) => const JHNoImplementationWidget(), + ), + text: 'Notification ', + ), ProfileListItem( onPressed: () {}, icon: themeNotifier.isDarkMode @@ -105,14 +125,110 @@ class SettingsPage extends StatelessWidget { value: themeNotifier.isDarkMode || false, ), ), + JHDisplayText( + text: 'Privacy', + style: TextStyle( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : CustomColors.indigoDark, + fontWeight: FontWeight.w700, + ), + fontSize: 27, + maxFontSize: 34, + ).hP16.vP16, + ProfileListItem( + icon: Icons.privacy_tip, + onPressed: () => showDialog( + context: context, + builder: (_) => const JHNoImplementationWidget(), + ), + text: 'Privacy policy', + ), ProfileListItem( - icon: LineAwesomeIcons.user_shield, + icon: Icons.file_copy, + onPressed: () => showDialog( + context: context, + builder: (_) => const JHNoImplementationWidget(), + ), + text: 'Impressum', + ), + ProfileListItem( + icon: Icons.contact_page_outlined, + onPressed: () => showDialog( + context: context, + builder: (_) => const JHNoImplementationWidget(), + ), + text: 'Terms and conditions', + isUnderLine: TextDecoration.underline, + ), + JHDisplayText( + text: 'Get us', + style: TextStyle( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : CustomColors.indigoDark, + fontWeight: FontWeight.w700, + ), + fontSize: 27, + maxFontSize: 34, + ).hP16.vP16, + ProfileListItem( + icon: Icons.rate_review, + onPressed: () => showDialog( + context: context, + builder: (_) => const JHNoImplementationWidget(), + ), + text: 'Rate us', + ), + ProfileListItem( + icon: LineAwesomeIcons.bug, + onPressed: () => showDialog( + context: context, + builder: (_) => const JHNoImplementationWidget(), + ), + text: 'Report Bug', + ), + ProfileListItem( + icon: Icons.contact_support_rounded, onPressed: () => showDialog( context: context, builder: (_) => const JHNoImplementationWidget(), ), text: 'Contact us', ), + ProfileListItem( + icon: Icons.recommend, + onPressed: () => showDialog( + context: context, + builder: (_) => const JHNoImplementationWidget(), + ), + text: 'Recommend App', + ), + ProfileListItem( + icon: Icons.question_answer, + onPressed: () => showDialog( + context: context, + builder: (_) => const JHNoImplementationWidget(), + ), + text: 'FAQ', + ), + const Center( + child: JHDisplayText( + text: 'Copyright© JordyHers-org', + fontSize: 8, + maxFontSize: 12, + style: TextStyle(color: Colors.grey), + ), + ).vTopP(25), + Center( + child: JHDisplayText( + text: 'v${appInfoService?.appInfo.version ?? ''}', + fontSize: 8, + maxFontSize: 12, + style: const TextStyle(color: Colors.grey), + ), + ), + const SizedBox(height: 32) ], ), ); @@ -121,51 +237,34 @@ class SettingsPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + elevation: 0, + leading: IconButton( + onPressed: () => Navigator.pop(context), + icon: Icon( + Icons.close_outlined, + size: 23, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : CustomColors.indigoDark, + ), + ), + ), body: Stack( children: [ - Align( - alignment: Alignment.topCenter, - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - onPressed: () => Navigator.pop(context), - icon: const Icon( - Icons.chevron_left, - size: 33, - ), - ), - IconButton( - onPressed: () => confirmSignOut(context, auth), - icon: const Icon( - Icons.logout, - size: 23, - ), - ), - ], - ), - buildItems(context), - const Center( - child: JHDisplayText( - text: 'Copyright© JordyHers-org', - fontSize: 8, - maxFontSize: 12, - style: TextStyle(color: Colors.grey), - ), - ), - Center( - child: JHDisplayText( - text: 'v${appInfoService?.appInfo.version ?? ''}', - fontSize: 8, - maxFontSize: 12, - style: const TextStyle(color: Colors.grey), - ), - ), - ], - ), - ).vP16.vP16, + Column( + children: [ + buildItems(context), + JHCustomButton( + title: 'Log out', + backgroundColor: Colors.red, + borderColor: Colors.red, + size: const Size(270, 50), + onPress: () async => confirmSignOut(context, auth), + ), + ], + ).vP8, ], ), ); @@ -179,11 +278,13 @@ class ProfileListItem extends StatelessWidget { this.icon, this.text, this.child, + this.isUnderLine = TextDecoration.none, this.hasNavigation = true, }) : super(key: key); final IconData? icon; final String? text; final bool hasNavigation; + final TextDecoration? isUnderLine; final VoidCallback onPressed; final Widget? child; @@ -194,11 +295,11 @@ class ProfileListItem extends StatelessWidget { MaterialStateColor.resolveWith((states) => Colors.transparent), onTap: onPressed, child: Container( - height: 55, + height: 45, margin: const EdgeInsets.symmetric( horizontal: 10, ).copyWith( - bottom: 20, + bottom: 10, ), padding: const EdgeInsets.symmetric( horizontal: 20, diff --git a/lib/app/helpers/parsing_extension.dart b/lib/app/helpers/parsing_extension.dart index 4c3c651..3f61ca7 100644 --- a/lib/app/helpers/parsing_extension.dart +++ b/lib/app/helpers/parsing_extension.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:intl/intl.dart'; import 'package:times_up_flutter/widgets/show_logger.dart'; @@ -137,3 +139,17 @@ double calculatePercentage(Duration duration) { JHLogger.$.d(parsedDuration); return res; } + +int getRandom(int maxValue) { + const minRange = 1; + final maxRange = maxValue; + final random = Random(); + + return minRange + random.nextInt(maxRange - minRange + 1); +} + +String convertToFormattedString(String input) { + final dateTime = DateTime.parse(input); + final formattedDate = DateFormat('MMMM d y HH:mma').format(dateTime); + return formattedDate; +} diff --git a/lib/app/lifecycle/life_cycle.dart b/lib/app/lifecycle/life_cycle.dart index 134d12c..780704c 100644 --- a/lib/app/lifecycle/life_cycle.dart +++ b/lib/app/lifecycle/life_cycle.dart @@ -1,25 +1,52 @@ import 'package:flutter/material.dart'; import 'package:times_up_flutter/widgets/show_logger.dart'; -class JHAppLifeCycleObserver extends WidgetsBindingObserver { +class JHAppLifecycleObserver extends StatefulWidget { + final Widget child; + + const JHAppLifecycleObserver({required this.child}); + + @override + _JHAppLifecycleObserverState createState() => _JHAppLifecycleObserverState(); +} + +class _JHAppLifecycleObserverState extends State + with WidgetsBindingObserver { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + } + @override - void didChangeAppLifecycleState(AppLifecycleState state) { - super.didChangeAppLifecycleState(state); + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + @override + Future didChangeAppLifecycleState(AppLifecycleState state) async { switch (state) { case AppLifecycleState.resumed: - JHLogger.$.d(state.name); + JHLogger.$.d('${state.name} - result: '); break; case AppLifecycleState.inactive: - JHLogger.$.d(state.name); + JHLogger.$.e('${state.name} - result: '); + break; case AppLifecycleState.paused: - JHLogger.$.d(state.name); + JHLogger.$.e('${state.name} - result:'); + break; case AppLifecycleState.detached: - JHLogger.$.d(state.name); - // App is detached from the view hierarchy + JHLogger.$.e('${state.name} - result: '); + break; } } + + @override + Widget build(BuildContext context) { + return widget.child; + } } diff --git a/lib/main_development.dart b/lib/main_development.dart index 287672b..8e4f6dc 100644 --- a/lib/main_development.dart +++ b/lib/main_development.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:provider/provider.dart'; import 'package:times_up_flutter/app/app.dart'; +import 'package:times_up_flutter/app/config/android_config.dart'; import 'package:times_up_flutter/bootstrap.dart'; import 'package:times_up_flutter/firebase_options_dev.dart'; import 'package:times_up_flutter/services/app_info_service.dart'; @@ -17,11 +18,12 @@ import 'package:times_up_flutter/theme/theme_notifier.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - PackageInfo packageInfo = await PackageInfo.fromPlatform(); + final packageInfo = await PackageInfo.fromPlatform(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ).whenComplete(() async { await _notificationServiceListener(); + await _backgroundListener(); }); await bootstrap( @@ -51,6 +53,10 @@ Future main() async { ); } +Future _backgroundListener() async { + await configureBackgroundFetch(); +} + Future _notificationServiceListener() async { final notificationService = NotificationService(); await notificationService.initialize().whenComplete( diff --git a/lib/models/notification_model/notification_model.dart b/lib/models/notification_model/notification_model.dart index 0a9a7bc..2ee288a 100644 --- a/lib/models/notification_model/notification_model.dart +++ b/lib/models/notification_model/notification_model.dart @@ -14,6 +14,7 @@ class NotificationModel with _$NotificationModel { required final String? body, required final String? message, required final String? id, + final DateTime? timeStamp, }) = _NotificationModel; factory NotificationModel.fromJson(Map json) => diff --git a/lib/models/notification_model/notification_model.freezed.dart b/lib/models/notification_model/notification_model.freezed.dart index b5f4d5d..5520d02 100644 --- a/lib/models/notification_model/notification_model.freezed.dart +++ b/lib/models/notification_model/notification_model.freezed.dart @@ -24,6 +24,7 @@ mixin _$NotificationModel { String? get body => throw _privateConstructorUsedError; String? get message => throw _privateConstructorUsedError; String? get id => throw _privateConstructorUsedError; + DateTime? get timeStamp => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -37,7 +38,12 @@ abstract class $NotificationModelCopyWith<$Res> { NotificationModel value, $Res Function(NotificationModel) then) = _$NotificationModelCopyWithImpl<$Res, NotificationModel>; @useResult - $Res call({String? title, String? body, String? message, String? id}); + $Res call( + {String? title, + String? body, + String? message, + String? id, + DateTime? timeStamp}); } /// @nodoc @@ -57,6 +63,7 @@ class _$NotificationModelCopyWithImpl<$Res, $Val extends NotificationModel> Object? body = freezed, Object? message = freezed, Object? id = freezed, + Object? timeStamp = freezed, }) { return _then(_value.copyWith( title: freezed == title @@ -75,6 +82,10 @@ class _$NotificationModelCopyWithImpl<$Res, $Val extends NotificationModel> ? _value.id : id // ignore: cast_nullable_to_non_nullable as String?, + timeStamp: freezed == timeStamp + ? _value.timeStamp + : timeStamp // ignore: cast_nullable_to_non_nullable + as DateTime?, ) as $Val); } } @@ -87,7 +98,12 @@ abstract class _$$_NotificationModelCopyWith<$Res> __$$_NotificationModelCopyWithImpl<$Res>; @override @useResult - $Res call({String? title, String? body, String? message, String? id}); + $Res call( + {String? title, + String? body, + String? message, + String? id, + DateTime? timeStamp}); } /// @nodoc @@ -105,6 +121,7 @@ class __$$_NotificationModelCopyWithImpl<$Res> Object? body = freezed, Object? message = freezed, Object? id = freezed, + Object? timeStamp = freezed, }) { return _then(_$_NotificationModel( title: freezed == title @@ -123,6 +140,10 @@ class __$$_NotificationModelCopyWithImpl<$Res> ? _value.id : id // ignore: cast_nullable_to_non_nullable as String?, + timeStamp: freezed == timeStamp + ? _value.timeStamp + : timeStamp // ignore: cast_nullable_to_non_nullable + as DateTime?, )); } } @@ -135,7 +156,8 @@ class _$_NotificationModel implements _NotificationModel { {required this.title, required this.body, required this.message, - required this.id}); + required this.id, + this.timeStamp}); factory _$_NotificationModel.fromJson(Map json) => _$$_NotificationModelFromJson(json); @@ -148,10 +170,12 @@ class _$_NotificationModel implements _NotificationModel { final String? message; @override final String? id; + @override + final DateTime? timeStamp; @override String toString() { - return 'NotificationModel(title: $title, body: $body, message: $message, id: $id)'; + return 'NotificationModel(title: $title, body: $body, message: $message, id: $id, timeStamp: $timeStamp)'; } @override @@ -162,12 +186,15 @@ class _$_NotificationModel implements _NotificationModel { (identical(other.title, title) || other.title == title) && (identical(other.body, body) || other.body == body) && (identical(other.message, message) || other.message == message) && - (identical(other.id, id) || other.id == id)); + (identical(other.id, id) || other.id == id) && + (identical(other.timeStamp, timeStamp) || + other.timeStamp == timeStamp)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash(runtimeType, title, body, message, id); + int get hashCode => + Object.hash(runtimeType, title, body, message, id, timeStamp); @JsonKey(ignore: true) @override @@ -189,7 +216,8 @@ abstract class _NotificationModel implements NotificationModel { {required final String? title, required final String? body, required final String? message, - required final String? id}) = _$_NotificationModel; + required final String? id, + final DateTime? timeStamp}) = _$_NotificationModel; factory _NotificationModel.fromJson(Map json) = _$_NotificationModel.fromJson; @@ -203,6 +231,8 @@ abstract class _NotificationModel implements NotificationModel { @override String? get id; @override + DateTime? get timeStamp; + @override @JsonKey(ignore: true) _$$_NotificationModelCopyWith<_$_NotificationModel> get copyWith => throw _privateConstructorUsedError; diff --git a/lib/models/notification_model/notification_model.g.dart b/lib/models/notification_model/notification_model.g.dart index a2b50bf..897207c 100644 --- a/lib/models/notification_model/notification_model.g.dart +++ b/lib/models/notification_model/notification_model.g.dart @@ -12,6 +12,9 @@ _$_NotificationModel _$$_NotificationModelFromJson(Map json) => body: json['body'] as String?, message: json['message'] as String?, id: json['id'] as String?, + timeStamp: json['timeStamp'] == null + ? null + : DateTime.parse(json['timeStamp'] as String), ); Map _$$_NotificationModelToJson( @@ -21,4 +24,5 @@ Map _$$_NotificationModelToJson( 'body': instance.body, 'message': instance.message, 'id': instance.id, + 'timeStamp': instance.timeStamp?.toIso8601String(), }; diff --git a/lib/services/database.dart b/lib/services/database.dart index 189caad..2d08265 100644 --- a/lib/services/database.dart +++ b/lib/services/database.dart @@ -1,5 +1,4 @@ import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:times_up_flutter/widgets/show_logger.dart'; import 'package:times_up_flutter/models/child_model/child_model.dart'; import 'package:times_up_flutter/models/email_model.dart'; import 'package:times_up_flutter/models/notification_model/notification_model.dart'; @@ -9,13 +8,13 @@ import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/services/firestore_service.dart'; import 'package:times_up_flutter/services/geo_locator_service.dart'; import 'package:times_up_flutter/utils/constants.dart'; +import 'package:times_up_flutter/widgets/show_logger.dart'; abstract class Database { Future setChild(ChildModel model); Future liveUpdateChild( ChildModel model, - int tick, AppUsageService apps, ); @@ -69,8 +68,6 @@ class FireStoreDatabase implements Database { final AuthBase auth; ChildModel? _child; - ChildModel get currentChild => _child!; - final _service = FireStoreService.instance; GeoLocatorService geo = GeoLocatorService(); @@ -107,7 +104,7 @@ class FireStoreDatabase implements Database { } Future setTokenOnFireStore(Map token) async { - await _service.setNotificationFunction( + await _service.setTokenFunction( path: APIPath.deviceToken(), data: token, ); @@ -150,20 +147,19 @@ class FireStoreDatabase implements Database { @override Future liveUpdateChild( ChildModel model, - int value, AppUsageService apps, ) async { await apps.getAppUsageService(); - //var point = await geo.getInitialLocation(); - //var currentLocation = GeoPoint(point.latitude, point.longitude); + final point = await geo.getInitialLocation(); + final currentLocation = GeoPoint(point.latitude, point.longitude); _child = ChildModel( id: model.id, name: model.name, email: model.email, token: model.token, - position: model.position, + position: currentLocation, appsUsageModel: apps.info, image: model.image, batteryLevel: model.batteryLevel, diff --git a/lib/services/firestore_service.dart b/lib/services/firestore_service.dart index 667b5cc..51a2af4 100644 --- a/lib/services/firestore_service.dart +++ b/lib/services/firestore_service.dart @@ -26,7 +26,7 @@ class FireStoreService { required Map data, }) async { final reference = FirebaseFirestore.instance.doc(path); - JHLogger.$.d('$path: $data'); + JHLogger.$.e('$path: $data'); await reference.update(data); } @@ -34,6 +34,16 @@ class FireStoreService { Future setNotificationFunction({ required String path, required Map data, + }) async { + final reference = FirebaseFirestore.instance.collection(path).doc(); + JHLogger.$.d('$path: $data'); + + await reference.set(data); + } + + Future setTokenFunction({ + required String path, + required Map data, }) async { final reference = FirebaseFirestore.instance.collection(path).doc(data['id'] as String?); diff --git a/lib/theme/theme.dart b/lib/theme/theme.dart index b581bc1..ec223c1 100644 --- a/lib/theme/theme.dart +++ b/lib/theme/theme.dart @@ -41,6 +41,7 @@ class AppTheme { ); static ThemeData darkTheme = ThemeData( + //textTheme: GoogleFonts.interTextTheme(), primarySwatch: buildMaterialColor(CustomColors.indigoDark), primaryColor: CustomColors.indigoDark, scaffoldBackgroundColor: CustomColors.indigoDarker, diff --git a/lib/widgets/jh_bar_chart.dart b/lib/widgets/jh_bar_chart.dart index b558226..5e9cebc 100644 --- a/lib/widgets/jh_bar_chart.dart +++ b/lib/widgets/jh_bar_chart.dart @@ -1,9 +1,7 @@ -import 'dart:math'; - import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; -import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; class JHAppUsageChart extends StatefulWidget { const JHAppUsageChart({ @@ -11,14 +9,7 @@ class JHAppUsageChart extends StatefulWidget { required this.name, Key? key, }) : super(key: key); - List get availableColors => const [ - Colors.purpleAccent, - Colors.yellow, - Colors.lightBlue, - Colors.orange, - Colors.pink, - Colors.redAccent, - ]; + final bool isEmpty; final String name; @@ -31,8 +22,6 @@ class JHAppUsageChartState extends State { int touchedIndex = -1; - bool isPlaying = false; - @override Widget build(BuildContext context) { return AspectRatio( @@ -73,7 +62,7 @@ class JHAppUsageChartState extends State { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: BarChart( - isPlaying ? randomData() : mainBarData(), + mainBarData(), swapAnimationDuration: animDuration, ), ), @@ -84,26 +73,6 @@ class JHAppUsageChartState extends State { ], ), ), - Padding( - padding: const EdgeInsets.all(4), - child: Align( - alignment: Alignment.topRight, - child: IconButton( - icon: Icon( - isPlaying ? Icons.pause : Icons.play_arrow, - color: Colors.pinkAccent, - ), - onPressed: () { - setState(() { - isPlaying = !isPlaying; - if (isPlaying) { - refreshState(); - } - }); - }, - ), - ), - ), ], ), ), @@ -349,72 +318,7 @@ class JHAppUsageChartState extends State { borderData: FlBorderData( show: false, ), - barGroups: List.generate(7, (i) { - switch (i) { - case 0: - return makeGroupData( - 0, - Random().nextInt(15).toDouble() + 6, - barColor: widget.availableColors[ - Random().nextInt(widget.availableColors.length)], - ); - case 1: - return makeGroupData( - 1, - Random().nextInt(15).toDouble() + 6, - barColor: widget.availableColors[ - Random().nextInt(widget.availableColors.length)], - ); - case 2: - return makeGroupData( - 2, - Random().nextInt(15).toDouble() + 6, - barColor: widget.availableColors[ - Random().nextInt(widget.availableColors.length)], - ); - case 3: - return makeGroupData( - 3, - Random().nextInt(15).toDouble() + 6, - barColor: widget.availableColors[ - Random().nextInt(widget.availableColors.length)], - ); - case 4: - return makeGroupData( - 4, - Random().nextInt(15).toDouble() + 6, - barColor: widget.availableColors[ - Random().nextInt(widget.availableColors.length)], - ); - case 5: - return makeGroupData( - 5, - Random().nextInt(15).toDouble() + 6, - barColor: widget.availableColors[ - Random().nextInt(widget.availableColors.length)], - ); - case 6: - return makeGroupData( - 6, - Random().nextInt(15).toDouble() + 6, - barColor: widget.availableColors[ - Random().nextInt(widget.availableColors.length)], - ); - default: - return throw Error(); - } - }), gridData: FlGridData(show: false), ); } - - Future refreshState() async { - setState(() {}); - await Future.delayed( - animDuration + const Duration(milliseconds: 50), - ); - if (isPlaying) { - await refreshState(); - } - } } diff --git a/lib/widgets/jh_custom_button.dart b/lib/widgets/jh_custom_button.dart index 1338f21..7b026f2 100644 --- a/lib/widgets/jh_custom_button.dart +++ b/lib/widgets/jh_custom_button.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/widgets/jh_size_config.dart'; -import 'package:times_up_flutter/theme/theme.dart'; class JHCustomButton extends StatelessWidget { const JHCustomButton({ @@ -11,12 +11,14 @@ class JHCustomButton extends StatelessWidget { Key? key, this.borderColor = Colors.transparent, this.textColor = Colors.white, + this.size, }) : super(key: key); final Color backgroundColor; final Color borderColor; final Color textColor; - final void Function() onPress; + final Size? size; final String title; + final void Function() onPress; @override Widget build(BuildContext context) { @@ -26,10 +28,11 @@ class JHCustomButton extends StatelessWidget { style: OutlinedButton.styleFrom( backgroundColor: backgroundColor, side: BorderSide(width: 1.5, color: borderColor), - minimumSize: Size( - MediaQuery.of(context).size.width * 0.95, - JHSizeConfig.screenHeight! * 0.07, - ), + minimumSize: size ?? + Size( + MediaQuery.of(context).size.width * 0.95, + JHSizeConfig.screenHeight! * 0.07, + ), ), onPressed: onPress, child: JHDisplayText( diff --git a/lib/widgets/jh_display_text.dart b/lib/widgets/jh_display_text.dart index ee80a1b..b489e67 100644 --- a/lib/widgets/jh_display_text.dart +++ b/lib/widgets/jh_display_text.dart @@ -9,9 +9,11 @@ class JHDisplayText extends StatelessWidget { this.fontSize, this.maxFontSize, this.maxLines, + this.textAlign, }) : super(key: key); final String text; final TextStyle style; + final TextAlign? textAlign; final double? fontSize; final double? maxFontSize; final int? maxLines; @@ -23,6 +25,7 @@ class JHDisplayText extends StatelessWidget { style: style, maxLines: maxLines ?? 10, textScaleFactor: 1, + textAlign: textAlign ?? TextAlign.start, minFontSize: fontSize ?? 13, maxFontSize: maxFontSize ?? 35, ); diff --git a/lib/widgets/jh_info_row_widget.dart b/lib/widgets/jh_info_row_widget.dart index bfd506c..94172a7 100644 --- a/lib/widgets/jh_info_row_widget.dart +++ b/lib/widgets/jh_info_row_widget.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/utils/data.dart'; import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/widgets/jh_info_bottom_sheet.dart'; import 'package:times_up_flutter/widgets/jh_info_box.dart'; import 'package:times_up_flutter/widgets/show_bottom_sheet.dart'; -import 'package:times_up_flutter/theme/theme.dart'; -import 'package:times_up_flutter/utils/data.dart'; class JHInfoRow extends StatelessWidget { const JHInfoRow({ @@ -39,6 +39,7 @@ class JHInfoRow extends StatelessWidget { child: JHDisplayText( text: dataOne.title, fontSize: 12, + textAlign: TextAlign.center, style: TextStyle( color: Colors.grey.shade500, ), diff --git a/lib/widgets/jh_line_chart.dart b/lib/widgets/jh_line_chart.dart new file mode 100644 index 0000000..1cb0625 --- /dev/null +++ b/lib/widgets/jh_line_chart.dart @@ -0,0 +1,289 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:times_up_flutter/app/helpers/parsing_extension.dart'; +import 'package:times_up_flutter/models/child_model/child_model.dart'; +import 'package:times_up_flutter/theme/theme.dart'; + +class JHLineChart extends StatelessWidget { + const JHLineChart({required this.model, Key? key}) : super(key: key); + final ChildModel model; + @override + Widget build(BuildContext context) { + return LineChart( + sampleData2, + swapAnimationDuration: const Duration(milliseconds: 250), + ); + } + + LineChartData get sampleData2 => LineChartData( + lineTouchData: lineTouchData2, + gridData: gridData, + titlesData: titlesData2, + borderData: borderData, + lineBarsData: lineBarsData2, + minX: 0, + maxX: 14, + maxY: 6, + minY: 0, + ); + + FlTitlesData get titlesData1 => FlTitlesData( + bottomTitles: AxisTitles( + sideTitles: bottomTitles, + ), + rightTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + topTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + leftTitles: AxisTitles( + sideTitles: leftTitles(), + ), + ); + + LineTouchData get lineTouchData2 => LineTouchData( + enabled: false, + ); + + FlTitlesData get titlesData2 => FlTitlesData( + bottomTitles: AxisTitles( + sideTitles: bottomTitles, + ), + rightTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + topTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + leftTitles: AxisTitles( + sideTitles: leftTitles(), + ), + ); + + List get lineBarsData2 => [ + lineChartBarData2_1, + lineChartBarData2_2, + lineChartBarData2_3, + ]; + + Widget leftTitleWidgets(double value, TitleMeta meta) { + const style = TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14, + ); + String text; + switch (value.toInt()) { + case 1: + text = '1m'; + break; + case 2: + text = '2m'; + break; + case 3: + text = '3m'; + break; + case 4: + text = '5m'; + break; + case 5: + text = '6m'; + break; + default: + return Container(); + } + + return Text(text, style: style, textAlign: TextAlign.center); + } + + SideTitles leftTitles() => SideTitles( + getTitlesWidget: leftTitleWidgets, + showTitles: true, + interval: 1, + reservedSize: 40, + ); + + Widget bottomTitleWidgets(double value, TitleMeta meta) { + const style = TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ); + Widget text; + switch (value.toInt()) { + case 2: + text = Image.memory( + model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] + .appIcon!, + height: 25, + ); + break; + case 4: + text = Image.memory( + model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] + .appIcon!, + height: 25, + ); + break; + case 6: + text = Image.memory( + model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] + .appIcon!, + height: 25, + ); + break; + case 8: + text = Image.memory( + model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] + .appIcon!, + height: 25, + ); + break; + case 10: + text = Image.memory( + model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] + .appIcon!, + height: 25, + ); + break; + default: + text = const Text(''); + break; + } + + return SideTitleWidget( + axisSide: meta.axisSide, + space: 10, + child: text, + ); + } + + SideTitles get bottomTitles => SideTitles( + showTitles: true, + reservedSize: 32, + interval: 1, + getTitlesWidget: bottomTitleWidgets, + ); + + FlGridData get gridData => FlGridData(show: false); + + FlBorderData get borderData => FlBorderData( + show: true, + border: Border( + bottom: BorderSide( + color: CustomColors.indigoDark.withOpacity(0.2), width: 4), + left: const BorderSide(color: Colors.transparent), + right: const BorderSide(color: Colors.transparent), + top: const BorderSide(color: Colors.transparent), + ), + ); + + LineChartBarData get lineChartBarData1_1 => LineChartBarData( + isCurved: true, + color: CustomColors.indigoDark, + barWidth: 8, + isStrokeCapRound: true, + dotData: FlDotData(show: false), + belowBarData: BarAreaData(show: false), + spots: const [ + FlSpot(1, 1), + FlSpot(3, 1.5), + FlSpot(5, 1.4), + FlSpot(7, 3.4), + FlSpot(10, 2), + FlSpot(12, 2.2), + FlSpot(13, 1.8), + ], + ); + + LineChartBarData get lineChartBarData1_2 => LineChartBarData( + isCurved: true, + color: CustomColors.indigoDark, + barWidth: 8, + isStrokeCapRound: true, + dotData: FlDotData(show: false), + belowBarData: BarAreaData( + show: false, + color: CustomColors.indigoDark.withOpacity(0), + ), + spots: const [ + FlSpot(1, 1), + FlSpot(3, 2.8), + FlSpot(7, 1.2), + FlSpot(10, 2.8), + FlSpot(12, 2.6), + FlSpot(13, 3.9), + ], + ); + + LineChartBarData get lineChartBarData1_3 => LineChartBarData( + isCurved: true, + color: CustomColors.greenPrimary, + barWidth: 8, + isStrokeCapRound: true, + dotData: FlDotData(show: false), + belowBarData: BarAreaData(show: false), + spots: const [ + FlSpot(1, 2.8), + FlSpot(3, 1.9), + FlSpot(6, 3), + FlSpot(10, 1.3), + FlSpot(13, 2.5), + ], + ); + + LineChartBarData get lineChartBarData2_1 => LineChartBarData( + isCurved: true, + curveSmoothness: 0, + color: CustomColors.greenPrimary.withOpacity(0.5), + barWidth: 4, + isStrokeCapRound: true, + dotData: FlDotData(show: false), + belowBarData: BarAreaData(show: false), + spots: const [ + FlSpot(1, 1), + FlSpot(3, 4), + FlSpot(5, 1.8), + FlSpot(7, 5), + FlSpot(10, 2), + FlSpot(12, 2.2), + FlSpot(13, 1.8), + ], + ); + + LineChartBarData get lineChartBarData2_2 => LineChartBarData( + isCurved: true, + color: CustomColors.indigoDark.withOpacity(0.5), + barWidth: 4, + isStrokeCapRound: true, + dotData: FlDotData(show: false), + belowBarData: BarAreaData( + show: true, + color: CustomColors.indigoDark.withOpacity(0.2), + ), + spots: const [ + FlSpot(1, 1), + FlSpot(3, 2.8), + FlSpot(7, 1.2), + FlSpot(10, 2.8), + FlSpot(12, 2.6), + FlSpot(13, 3.9), + ], + ); + + LineChartBarData get lineChartBarData2_3 => LineChartBarData( + isCurved: true, + curveSmoothness: 0, + color: CustomColors.indigoDark.withOpacity(0.5), + barWidth: 2, + isStrokeCapRound: true, + dotData: FlDotData(show: true), + belowBarData: BarAreaData(show: false), + spots: const [ + FlSpot(1, 3.8), + FlSpot(3, 1.9), + FlSpot(6, 5), + FlSpot(10, 3.3), + FlSpot(13, 4.5), + ], + ); +} diff --git a/lib/widgets/jh_no_implementation.dart b/lib/widgets/jh_no_implementation.dart index d49a73b..65ba96c 100644 --- a/lib/widgets/jh_no_implementation.dart +++ b/lib/widgets/jh_no_implementation.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:line_awesome_flutter/line_awesome_flutter.dart'; +import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/widgets/jh_custom_raised_button.dart'; import 'package:times_up_flutter/widgets/jh_display_text.dart'; -import 'package:times_up_flutter/theme/theme.dart'; class JHNoImplementationWidget extends StatelessWidget { const JHNoImplementationWidget({ @@ -29,19 +28,38 @@ class JHNoImplementationWidget extends StatelessWidget { child: Center( child: Column( children: [ - const Icon(LineAwesomeIcons.info), - JHDisplayText( - text: title ?? 'Oops :( ', - style: const TextStyle(fontWeight: FontWeight.w500), + Row( + children: [ + const Spacer(), + JHDisplayText( + text: title ?? 'Oops ', + style: const TextStyle(fontWeight: FontWeight.w500), + ), + const Icon(Icons.error), + const Spacer(), + ], ), const SizedBox(height: 8), + JHDisplayText( + text: content ?? 'Not implemented yet.', + fontSize: 17, + style: TextStyle( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : CustomColors.indigoDark, + fontWeight: FontWeight.w700, + ), + ).vP16, JHDisplayText( text: content ?? - 'Not implemented yet. We are actively working to' + 'We are actively working to' ' implement ' ' that we will let you know soon.', - style: const TextStyle( - color: Colors.grey, + textAlign: TextAlign.center, + style: TextStyle( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : CustomColors.indigoDark, fontWeight: FontWeight.w400, ), ).vP16, diff --git a/lib/widgets/jh_shimmer_map.dart b/lib/widgets/jh_shimmer_map.dart new file mode 100644 index 0000000..a6d9190 --- /dev/null +++ b/lib/widgets/jh_shimmer_map.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:shimmer/shimmer.dart'; + +class ShimmerMap extends StatelessWidget { + const ShimmerMap({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Shimmer.fromColors( + baseColor: Theme.of(context).scaffoldBackgroundColor, + highlightColor: Theme.of(context).scaffoldBackgroundColor, + child: Container( + color: Theme.of(context).scaffoldBackgroundColor, + width: double.infinity, + height: MediaQuery.of(context).size.height, + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index c4690d0..b826d01 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -57,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + background_fetch: + dependency: "direct main" + description: + name: background_fetch + sha256: f70b28a0f7a3156195e9742229696f004ea3bf10f74039b7bf4c78a74fbda8a4 + url: "https://pub.dev" + source: hosted + version: "1.2.1" battery_plus: dependency: "direct main" description: @@ -221,10 +229,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.17.1" convert: dependency: transitive description: @@ -905,10 +913,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.18.0" io: dependency: transitive description: @@ -985,18 +993,18 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.15" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.2.0" meta: dependency: transitive description: @@ -1333,6 +1341,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" + shimmer: + dependency: "direct main" + description: + name: shimmer + sha256: "1f1009b5845a1f88f1c5630212279540486f97409e9fc3f63883e71070d107bf" + url: "https://pub.dev" + source: hosted + version: "2.0.0" showcaseview: dependency: "direct main" description: @@ -1382,10 +1398,10 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.9.1" stack_trace: dependency: transitive description: @@ -1430,26 +1446,26 @@ packages: dependency: "direct main" description: name: test - sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" + sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4" url: "https://pub.dev" source: hosted - version: "1.24.3" + version: "1.24.1" test_api: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.5.1" test_core: dependency: transitive description: name: test_core - sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" + sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93" url: "https://pub.dev" source: hosted - version: "0.5.3" + version: "0.5.1" timezone: dependency: transitive description: @@ -1578,14 +1594,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" - web: - dependency: transitive - description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 - url: "https://pub.dev" - source: hosted - version: "0.1.4-beta" web_socket_channel: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 45154eb..3342930 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: # Notification Packages: firebase_messaging: ^14.4.0 flutter_local_notifications: ^14.0.0-dev.2 + background_fetch: ^1.2.1 # Utility Packages: intl: any @@ -54,6 +55,7 @@ dependencies: # UI Component Packages: line_awesome_flutter: ^2.0.0 showcaseview: ^2.0.3 + shimmer: ^2.0.0 # Testing Packages: diff --git a/test/helpers/test_helpers.mocks.dart b/test/helpers/test_helpers.mocks.dart index 0fa3c9f..609286f 100644 --- a/test/helpers/test_helpers.mocks.dart +++ b/test/helpers/test_helpers.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.4.0 from annotations +// Mocks generated by Mockito 5.4.2 from annotations // in times_up_flutter/test/helpers/test_helpers.dart. // Do not manually edit this file. @@ -381,7 +381,6 @@ class MockDatabase extends _i1.Mock implements _i10.Database { @override _i9.Future liveUpdateChild( _i3.ChildModel? model, - int? tick, _i11.AppUsageService? apps, ) => (super.noSuchMethod( @@ -389,7 +388,6 @@ class MockDatabase extends _i1.Mock implements _i10.Database { #liveUpdateChild, [ model, - tick, apps, ], ), @@ -1248,18 +1246,6 @@ class MockFireStoreDatabase extends _i1.Mock implements _i10.FireStoreDatabase { returnValueForMissingStub: null, ); @override - _i3.ChildModel get currentChild => (super.noSuchMethod( - Invocation.getter(#currentChild), - returnValue: _FakeChildModel_1( - this, - Invocation.getter(#currentChild), - ), - returnValueForMissingStub: _FakeChildModel_1( - this, - Invocation.getter(#currentChild), - ), - ) as _i3.ChildModel); - @override _i9.Future setChild(_i3.ChildModel? model) => (super.noSuchMethod( Invocation.method( #setChild, @@ -1368,7 +1354,6 @@ class MockFireStoreDatabase extends _i1.Mock implements _i10.FireStoreDatabase { @override _i9.Future liveUpdateChild( _i3.ChildModel? model, - int? value, _i11.AppUsageService? apps, ) => (super.noSuchMethod( @@ -1376,7 +1361,6 @@ class MockFireStoreDatabase extends _i1.Mock implements _i10.FireStoreDatabase { #liveUpdateChild, [ model, - value, apps, ], ), diff --git a/test/services/firestore_service_test.dart b/test/services/firestore_service_test.dart index 2a9d71e..359c04c 100644 --- a/test/services/firestore_service_test.dart +++ b/test/services/firestore_service_test.dart @@ -17,6 +17,6 @@ void main() { // Replace with your ChildModel instance const tick = 5; // Replace with your tick value - await database.liveUpdateChild(Dummy.childModel, tick, usage); + await database.liveUpdateChild(Dummy.childModel, usage); }); } From c0f1576422e9bf8b6d6a0115b96edd15da02a8ff Mon Sep 17 00:00:00 2001 From: jordyhers Date: Fri, 20 Oct 2023 09:50:47 +0200 Subject: [PATCH 05/23] fix(#154): completely revamp app look --- .idea/runConfigurations/development.xml | 7 +++++++ .idea/runConfigurations/production.xml | 7 +++++++ .idea/runConfigurations/staging.xml | 7 +++++++ lib/app/features/parent_side/notification_page.dart | 1 + 4 files changed, 22 insertions(+) create mode 100644 .idea/runConfigurations/development.xml create mode 100644 .idea/runConfigurations/production.xml create mode 100644 .idea/runConfigurations/staging.xml diff --git a/.idea/runConfigurations/development.xml b/.idea/runConfigurations/development.xml new file mode 100644 index 0000000..07b02c6 --- /dev/null +++ b/.idea/runConfigurations/development.xml @@ -0,0 +1,7 @@ + + + + diff --git a/.idea/runConfigurations/production.xml b/.idea/runConfigurations/production.xml new file mode 100644 index 0000000..1c5c774 --- /dev/null +++ b/.idea/runConfigurations/production.xml @@ -0,0 +1,7 @@ + + + + diff --git a/.idea/runConfigurations/staging.xml b/.idea/runConfigurations/staging.xml new file mode 100644 index 0000000..f979a68 --- /dev/null +++ b/.idea/runConfigurations/staging.xml @@ -0,0 +1,7 @@ + + + + diff --git a/lib/app/features/parent_side/notification_page.dart b/lib/app/features/parent_side/notification_page.dart index 99b5282..4ae3823 100644 --- a/lib/app/features/parent_side/notification_page.dart +++ b/lib/app/features/parent_side/notification_page.dart @@ -16,6 +16,7 @@ import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; enum AppState { loaded, empty } +// class NotificationPage extends StatefulWidget { const NotificationPage({ required this.auth, From 37dad1045af5833f59ec1bd4f287c4d93f6fd1c0 Mon Sep 17 00:00:00 2001 From: jordyhers Date: Fri, 20 Oct 2023 10:25:17 +0200 Subject: [PATCH 06/23] fix(#154): set value to 0 if empty --- .../features/parent_side/edit_child_page.dart | 1 + lib/widgets/jh_line_chart.dart | 78 ++++++++++++------- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/lib/app/features/parent_side/edit_child_page.dart b/lib/app/features/parent_side/edit_child_page.dart index 729e501..5fdafbd 100644 --- a/lib/app/features/parent_side/edit_child_page.dart +++ b/lib/app/features/parent_side/edit_child_page.dart @@ -162,6 +162,7 @@ class _EditChildPageState extends State { @override Widget build(BuildContext context) { return Scaffold( + resizeToAvoidBottomInset: false, floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, floatingActionButton: JHCustomRaisedButton( width: MediaQuery.of(context).size.width * 0.80, diff --git a/lib/widgets/jh_line_chart.dart b/lib/widgets/jh_line_chart.dart index 1cb0625..b64afe1 100644 --- a/lib/widgets/jh_line_chart.dart +++ b/lib/widgets/jh_line_chart.dart @@ -104,46 +104,66 @@ class JHLineChart extends StatelessWidget { ); Widget bottomTitleWidgets(double value, TitleMeta meta) { - const style = TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ); Widget text; + + if (model.appsUsageModel.isEmpty) { + text = Text('0'); + } switch (value.toInt()) { case 2: - text = Image.memory( - model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] - .appIcon!, - height: 25, - ); + if (model.appsUsageModel.isEmpty) { + text = Text('0'); + } else { + text = Image.memory( + model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] + .appIcon!, + height: 25, + ); + } break; case 4: - text = Image.memory( - model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] - .appIcon!, - height: 25, - ); + if (model.appsUsageModel.isEmpty) { + text = Text('0'); + } else { + text = Image.memory( + model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] + .appIcon!, + height: 25, + ); + } break; case 6: - text = Image.memory( - model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] - .appIcon!, - height: 25, - ); + if (model.appsUsageModel.isEmpty) { + text = Text('0'); + } else { + text = Image.memory( + model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] + .appIcon!, + height: 25, + ); + } break; case 8: - text = Image.memory( - model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] - .appIcon!, - height: 25, - ); + if (model.appsUsageModel.isEmpty) { + text = Text('0'); + } else { + text = Image.memory( + model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] + .appIcon!, + height: 25, + ); + } break; case 10: - text = Image.memory( - model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] - .appIcon!, - height: 25, - ); + if (model.appsUsageModel.isEmpty) { + text = Text('0'); + } else { + text = Image.memory( + model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] + .appIcon!, + height: 25, + ); + } break; default: text = const Text(''); From 642784168474c788f8ec9e10cc9691bc2bd25439 Mon Sep 17 00:00:00 2001 From: jordyhers Date: Fri, 20 Oct 2023 10:28:31 +0200 Subject: [PATCH 07/23] fix(#154): fix linting error --- lib/app/config/android_config.dart | 4 ++-- lib/app/features/parent_side/app_list_page.dart | 3 ++- lib/app/lifecycle/life_cycle.dart | 5 +++-- lib/widgets/jh_feature_widget.dart | 2 +- lib/widgets/jh_header.dart | 2 +- lib/widgets/jh_info_bottom_sheet.dart | 2 +- lib/widgets/jh_line_chart.dart | 14 +++++++------- test/services/firestore_service_test.dart | 3 --- 8 files changed, 17 insertions(+), 18 deletions(-) diff --git a/lib/app/config/android_config.dart b/lib/app/config/android_config.dart index 62507b9..56820f8 100644 --- a/lib/app/config/android_config.dart +++ b/lib/app/config/android_config.dart @@ -30,7 +30,7 @@ Future configureBackgroundFetch() async { backgroundFetchHeadlessTask, ).then((int status) { JHLogger.$.e('[BackgroundFetch] Headless task timed-out- $status'); - }).catchError((e) { - JHLogger.$.d("[BackgroundFetch] configure ERROR: $e"); + }).catchError((Object e) { + JHLogger.$.d('[BackgroundFetch] configure ERROR: $e'); }); } diff --git a/lib/app/features/parent_side/app_list_page.dart b/lib/app/features/parent_side/app_list_page.dart index f6f16ce..bd91364 100644 --- a/lib/app/features/parent_side/app_list_page.dart +++ b/lib/app/features/parent_side/app_list_page.dart @@ -48,7 +48,8 @@ class AppListPage extends StatelessWidget { ), body: ListView.builder( physics: const BouncingScrollPhysics( - decelerationRate: ScrollDecelerationRate.fast), + decelerationRate: ScrollDecelerationRate.fast, + ), itemCount: childModel.appsUsageModel.length, itemBuilder: (context, index) { return Column( diff --git a/lib/app/lifecycle/life_cycle.dart b/lib/app/lifecycle/life_cycle.dart index 780704c..abc1d27 100644 --- a/lib/app/lifecycle/life_cycle.dart +++ b/lib/app/lifecycle/life_cycle.dart @@ -2,11 +2,12 @@ import 'package:flutter/material.dart'; import 'package:times_up_flutter/widgets/show_logger.dart'; class JHAppLifecycleObserver extends StatefulWidget { + const JHAppLifecycleObserver({required this.child, Key? key}) + : super(key: key); final Widget child; - const JHAppLifecycleObserver({required this.child}); - @override + // ignore: library_private_types_in_public_api _JHAppLifecycleObserverState createState() => _JHAppLifecycleObserverState(); } diff --git a/lib/widgets/jh_feature_widget.dart b/lib/widgets/jh_feature_widget.dart index e6086bb..bd9e9ce 100644 --- a/lib/widgets/jh_feature_widget.dart +++ b/lib/widgets/jh_feature_widget.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; class JHFeatureWidget extends StatelessWidget { const JHFeatureWidget({ diff --git a/lib/widgets/jh_header.dart b/lib/widgets/jh_header.dart index a449328..a63672a 100644 --- a/lib/widgets/jh_header.dart +++ b/lib/widgets/jh_header.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; class JHHeader extends StatelessWidget { const JHHeader({ diff --git a/lib/widgets/jh_info_bottom_sheet.dart b/lib/widgets/jh_info_bottom_sheet.dart index f0a4519..f1068a9 100644 --- a/lib/widgets/jh_info_bottom_sheet.dart +++ b/lib/widgets/jh_info_bottom_sheet.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; class JHBottomSheet extends StatelessWidget { const JHBottomSheet({ diff --git a/lib/widgets/jh_line_chart.dart b/lib/widgets/jh_line_chart.dart index b64afe1..c34661b 100644 --- a/lib/widgets/jh_line_chart.dart +++ b/lib/widgets/jh_line_chart.dart @@ -107,12 +107,12 @@ class JHLineChart extends StatelessWidget { Widget text; if (model.appsUsageModel.isEmpty) { - text = Text('0'); + text = const Text('0'); } switch (value.toInt()) { case 2: if (model.appsUsageModel.isEmpty) { - text = Text('0'); + text = const Text('0'); } else { text = Image.memory( model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] @@ -123,7 +123,7 @@ class JHLineChart extends StatelessWidget { break; case 4: if (model.appsUsageModel.isEmpty) { - text = Text('0'); + text = const Text('0'); } else { text = Image.memory( model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] @@ -134,7 +134,7 @@ class JHLineChart extends StatelessWidget { break; case 6: if (model.appsUsageModel.isEmpty) { - text = Text('0'); + text = const Text('0'); } else { text = Image.memory( model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] @@ -145,7 +145,7 @@ class JHLineChart extends StatelessWidget { break; case 8: if (model.appsUsageModel.isEmpty) { - text = Text('0'); + text = const Text('0'); } else { text = Image.memory( model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] @@ -156,7 +156,7 @@ class JHLineChart extends StatelessWidget { break; case 10: if (model.appsUsageModel.isEmpty) { - text = Text('0'); + text = const Text('0'); } else { text = Image.memory( model.appsUsageModel[getRandom(model.appsUsageModel.length - 1)] @@ -190,7 +190,7 @@ class JHLineChart extends StatelessWidget { show: true, border: Border( bottom: BorderSide( - color: CustomColors.indigoDark.withOpacity(0.2), width: 4), + color: CustomColors.indigoDark.withOpacity(0.2), width: 4,), left: const BorderSide(color: Colors.transparent), right: const BorderSide(color: Colors.transparent), top: const BorderSide(color: Colors.transparent), diff --git a/test/services/firestore_service_test.dart b/test/services/firestore_service_test.dart index 359c04c..b717826 100644 --- a/test/services/firestore_service_test.dart +++ b/test/services/firestore_service_test.dart @@ -7,15 +7,12 @@ import '../mocks.dart'; void main() { test('setChild', () async { final database = MockDatabase(); - // Replace with your ChildModel instance await database.setChild(Dummy.childModel); }); test('liveUpdateChild', () async { final database = MockDatabase(); final usage = AppUsageService(); - // Replace with your ChildModel instance - const tick = 5; // Replace with your tick value await database.liveUpdateChild(Dummy.childModel, usage); }); From b5fcce40087aaa307bebe49afde0f90b6467c406 Mon Sep 17 00:00:00 2001 From: Jordy Hershel Igondjo <49708438+JordyHers@users.noreply.github.com> Date: Fri, 20 Oct 2023 10:42:07 +0200 Subject: [PATCH 08/23] chore(#124): fix read me screeshots --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 658406e..dec0439 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ settled for user, and doesn't collect data for third parties companies. | | | | |-|-|-| | Onboarding | Sign_in_page | child_list_page -| ChildDetailsPage | ChildNotificationRemoval | GuidedTour -| NotificationSending | ChildLocation | settings_page | +| ChildDetailsPage | ChildNotificationRemoval | GuidedTour +| NotificationSending | ChildLocation | settings_page | ## Application Feature: Child Side From 931a0a0a52b7dc5bc3045c055389b34eceb61a34 Mon Sep 17 00:00:00 2001 From: CHAN Kelwin Hillary <5429312+ckelwin@users.noreply.github.com> Date: Sat, 21 Oct 2023 20:02:19 +0800 Subject: [PATCH 09/23] fix(#188): Made child picture not mandatory when adding a new child. A default icon will be displayed as a substitute. --- .../parent_side/child_details_page.dart | 83 +++++++++---------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/lib/app/features/parent_side/child_details_page.dart b/lib/app/features/parent_side/child_details_page.dart index 82e7341..f19bafe 100644 --- a/lib/app/features/parent_side/child_details_page.dart +++ b/lib/app/features/parent_side/child_details_page.dart @@ -128,53 +128,52 @@ class _ChildDetailsPageState extends State return [ SliverAppBar( actions: [ - if (model.image != null) - Row( - children: [ - GestureDetector( - onTap: () => showCustomBottomSheet( - context, - animationController: _animationController, - child: Container( - decoration: BoxDecoration( - color: themeData.scaffoldBackgroundColor, - ), - height: 200, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Spacer(), - JHCustomButton( - title: ' Bed Time', - backgroundColor: Colors.indigo, - onPress: () async => _sendNotification( - context, - model, - 'Hey Go to bed Now', - ), + Row( + children: [ + GestureDetector( + onTap: () => showCustomBottomSheet( + context, + animationController: _animationController, + child: Container( + decoration: BoxDecoration( + color: themeData.scaffoldBackgroundColor, + ), + height: 200, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Spacer(), + JHCustomButton( + title: ' Bed Time', + backgroundColor: Colors.indigo, + onPress: () async => _sendNotification( + context, + model, + 'Hey Go to bed Now', ), - JHCustomButton( - title: 'Homework Time', - backgroundColor: CustomColors.indigoLight, - onPress: () async => _sendNotification( - context, - model, - 'Homework Time', - ), + ), + JHCustomButton( + title: 'Homework Time', + backgroundColor: CustomColors.indigoLight, + onPress: () async => _sendNotification( + context, + model, + 'Homework Time', ), - const Spacer(), - ], - ), + ), + const Spacer(), + ], ), ), - child: ClipOval( - child: Image.network(model.image!), - ).p4, ), - ], - ) - else - const SizedBox.shrink(), + child: ClipOval( + child: model.image != null + ? Image.network(model.image!) + : const Icon(Icons.person), + ).p4, + ), + ], + ), ], elevation: 0.5, shadowColor: CustomColors.indigoLight, From 1af26b28860596c69425f1e637a8ccbb2c9ad02a Mon Sep 17 00:00:00 2001 From: CHAN Kelwin Hillary <5429312+ckelwin@users.noreply.github.com> Date: Sat, 21 Oct 2023 20:09:23 +0800 Subject: [PATCH 10/23] chore: Revert changes on line 273/274. --- lib/app/features/parent_side/child_details_page.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/app/features/parent_side/child_details_page.dart b/lib/app/features/parent_side/child_details_page.dart index f19bafe..13f491a 100644 --- a/lib/app/features/parent_side/child_details_page.dart +++ b/lib/app/features/parent_side/child_details_page.dart @@ -270,8 +270,7 @@ class _ChildDetailsPageState extends State context, widget.childModel, ), - ), - const SizedBox(height: 40), + ).vTopP(70), ]), ), ], From 2f5301a507dc028d03eeeab7f9c6c68c8e0f9578 Mon Sep 17 00:00:00 2001 From: jordyhers Date: Sat, 21 Oct 2023 22:58:18 +0200 Subject: [PATCH 11/23] fix(#154): fix issue with multiple notification not sent --- lib/app/features/parent_side/notification_page.dart | 3 ++- lib/services/api_path.dart | 4 ++-- lib/services/database.dart | 6 +++--- lib/services/firestore_service.dart | 12 ++++++++---- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/app/features/parent_side/notification_page.dart b/lib/app/features/parent_side/notification_page.dart index 4ae3823..ed60d70 100644 --- a/lib/app/features/parent_side/notification_page.dart +++ b/lib/app/features/parent_side/notification_page.dart @@ -51,7 +51,8 @@ class _NotificationPageState extends State { Future _delete(BuildContext context, NotificationModel model) async { try { - await widget.database?.deleteNotification(model.id!); + await widget.database + ?.deleteNotification(model.timeStamp!.toIso8601String()); } on FirebaseException catch (e) { await showExceptionAlertDialog( context, diff --git a/lib/services/api_path.dart b/lib/services/api_path.dart index af61430..3279955 100644 --- a/lib/services/api_path.dart +++ b/lib/services/api_path.dart @@ -4,8 +4,8 @@ class APIPath { static String children(String uid) => 'users/$uid/child/'; - static String notifications(String uid, String childId) => - 'users/$uid/notifications/$childId'; + static String notifications(String uid, String timestamp) => + 'users/$uid/notifications/$timestamp'; static String notificationsStream(String uid, String childId) => 'users/$uid/notifications/'; diff --git a/lib/services/database.dart b/lib/services/database.dart index 2d08265..6c36418 100644 --- a/lib/services/database.dart +++ b/lib/services/database.dart @@ -22,7 +22,7 @@ abstract class Database { Future deleteChild(ChildModel model); - Future deleteNotification(String id); + Future deleteNotification(String timestamp); Stream> childrenStream(); @@ -119,8 +119,8 @@ class FireStoreDatabase implements Database { } @override - Future deleteNotification(String id) async { - await _service.deleteData(path: APIPath.notifications(uid, id)); + Future deleteNotification(String timestamp) async { + await _service.deleteData(path: APIPath.notifications(uid, timestamp)); } @override diff --git a/lib/services/firestore_service.dart b/lib/services/firestore_service.dart index 51a2af4..537bdcb 100644 --- a/lib/services/firestore_service.dart +++ b/lib/services/firestore_service.dart @@ -2,7 +2,6 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_storage/firebase_storage.dart'; -import 'package:flutter/foundation.dart'; import 'package:times_up_flutter/widgets/show_logger.dart'; typedef QueryBuilder = T Function(Map data); @@ -35,7 +34,9 @@ class FireStoreService { required String path, required Map data, }) async { - final reference = FirebaseFirestore.instance.collection(path).doc(); + final reference = FirebaseFirestore.instance + .collection(path) + .doc(data['timeStamp'] as String); JHLogger.$.d('$path: $data'); await reference.set(data); @@ -78,8 +79,11 @@ class FireStoreService { await reference.delete(); } - debugPrint('delete: $path'); - await reference.delete(); + try { + await reference.delete(); + } catch (e) { + JHLogger.$.e(e); + } } Stream> collectionStream({ From cba844c7ad4976773d3d330aa87315af64ea82f7 Mon Sep 17 00:00:00 2001 From: CHAN Kelwin Hillary <5429312+ckelwin@users.noreply.github.com> Date: Sun, 22 Oct 2023 19:57:36 +0800 Subject: [PATCH 12/23] fix(#220): Fixed error when notification has null timestamp. Updated datetime formatting to show time correctly for 'PM'. --- lib/app/features/parent_side/notification_page.dart | 2 +- lib/app/helpers/parsing_extension.dart | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/app/features/parent_side/notification_page.dart b/lib/app/features/parent_side/notification_page.dart index 4ae3823..c6812aa 100644 --- a/lib/app/features/parent_side/notification_page.dart +++ b/lib/app/features/parent_side/notification_page.dart @@ -176,7 +176,7 @@ class _NotificationPageState extends State { subtitle: JHDisplayText( textAlign: TextAlign.start, text: convertToFormattedString( - data[index].timeStamp.toString(), + data[index].timeStamp, ), style: const TextStyle( fontWeight: FontWeight.w400, diff --git a/lib/app/helpers/parsing_extension.dart b/lib/app/helpers/parsing_extension.dart index 3f61ca7..2d90ad0 100644 --- a/lib/app/helpers/parsing_extension.dart +++ b/lib/app/helpers/parsing_extension.dart @@ -148,8 +148,8 @@ int getRandom(int maxValue) { return minRange + random.nextInt(maxRange - minRange + 1); } -String convertToFormattedString(String input) { - final dateTime = DateTime.parse(input); - final formattedDate = DateFormat('MMMM d y HH:mma').format(dateTime); +String convertToFormattedString(DateTime? dateTime) { + final formattedDate = + dateTime != null ? DateFormat('MMMM d y hh:mm a').format(dateTime) : ''; return formattedDate; } From 828544537571c78c7657000c7e8452cf06337b4d Mon Sep 17 00:00:00 2001 From: jordyhers Date: Wed, 25 Oct 2023 11:58:22 +0200 Subject: [PATCH 13/23] fix(#154): refactor database --- lib/services/database.dart | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/services/database.dart b/lib/services/database.dart index 6c36418..5eacf87 100644 --- a/lib/services/database.dart +++ b/lib/services/database.dart @@ -13,17 +13,14 @@ import 'package:times_up_flutter/widgets/show_logger.dart'; abstract class Database { Future setChild(ChildModel model); - Future liveUpdateChild( - ChildModel model, - AppUsageService apps, - ); - Future updateChild(ChildModel model); Future deleteChild(ChildModel model); Future deleteNotification(String timestamp); + Future sendEmail({required EmailModel email}); + Stream> childrenStream(); Stream> notificationStream({String childId}); @@ -35,7 +32,10 @@ abstract class Database { ChildModel model, ); - Future sendEmail({required EmailModel email}); + Future liveUpdateChild( + ChildModel model, + AppUsageService apps, + ); Future getUserCurrentChild( String key, @@ -67,7 +67,6 @@ class FireStoreDatabase implements Database { final String uid; final AuthBase auth; ChildModel? _child; - final _service = FireStoreService.instance; GeoLocatorService geo = GeoLocatorService(); From d58bafab42a5dc4b462f9dab81fb0258d97bba4d Mon Sep 17 00:00:00 2001 From: bhoomikshetty Date: Wed, 25 Oct 2023 18:25:45 +0530 Subject: [PATCH 14/23] fix(#223) : Displaying notification sent to other children in Notification screen --- lib/app/features/child_side/child_page.dart | 6 +++--- lib/services/firestore_service.dart | 9 ++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/app/features/child_side/child_page.dart b/lib/app/features/child_side/child_page.dart index 3e06c4e..3a42302 100644 --- a/lib/app/features/child_side/child_page.dart +++ b/lib/app/features/child_side/child_page.dart @@ -216,7 +216,7 @@ class _ChildPageState extends State with WidgetsBindingObserver { } else if (state is ChildSideFetching) { return _buildLoading(); } else if (state is ChildSideNotification) { - return _buildNotification(); + return _buildNotification(widget.child!); } else if (state is ChildSideAppList) { return _buildAppList(widget.appUsage); } else { @@ -250,9 +250,9 @@ class _ChildPageState extends State with WidgetsBindingObserver { ); } - Widget _buildNotification() { + Widget _buildNotification(ChildModel child) { return StreamBuilder>( - stream: widget.database!.notificationStream(childId: ''), + stream: widget.database!.notificationStream(childId: child.id), builder: (BuildContext context, snapshot) { if (snapshot.hasData) { final data = snapshot.data; diff --git a/lib/services/firestore_service.dart b/lib/services/firestore_service.dart index 51a2af4..c412d4e 100644 --- a/lib/services/firestore_service.dart +++ b/lib/services/firestore_service.dart @@ -3,6 +3,7 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/foundation.dart'; +import 'package:times_up_flutter/models/notification_model/notification_model.dart'; import 'package:times_up_flutter/widgets/show_logger.dart'; typedef QueryBuilder = T Function(Map data); @@ -110,6 +111,7 @@ class FireStoreService { Stream> notificationStream({ required String path, required T Function(Map data, String documentId) builder, + String? childId, Function(Query query)? queryBuilder, int Function(T lhs, T rhs)? sort, }) { @@ -118,10 +120,15 @@ class FireStoreService { query = queryBuilder(query) as CollectionReference>; } final snapshots = query.snapshots(); + return snapshots.map((snapshot) { final result = snapshot.docs .map((snapshot) => builder(snapshot.data(), snapshot.id)) - .where((value) => value != null) + .where( + (value) => + value != null && + (childId == null || (value as NotificationModel).id == childId), + ) .toList(); if (sort != null) { result.sort(sort); From d12c87c6029f108091d22b6237e3768362cf4426 Mon Sep 17 00:00:00 2001 From: Jordy Hershel Igondjo <49708438+JordyHers@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:12:03 +0200 Subject: [PATCH 15/23] chore: create `CONTRIBUTING.md` --- CONTRIBUTING.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4002c20 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,32 @@ +## How to Contribute + +1. **Read The Branch naming convention** + > How to name a branch + +2. **Fork and Clone the Project** + ```bash + git clone https://github.com/JordyHers-org/Times-up-flutter.git + cd Times-up-flutter/ + ``` + +3. **Install Flutter Version** + > Install FVM via Homebrew and use Flutter version 3.7.12. + ```bash + + brew install fvm + fvm install 3.7.12 + ``` + +4. **Request Firebase Options File** + > Request the Firebase options file from the Project Owner and place it in the appropriate location. From discord server +Jordyhers [Discord- JordyHers](https://discord.gg/e4ppDx9Zcy) + +5. **Extra** + > For child's pictures feel free to use any of the pictures available. + +| | | | +|-|-|-| +| Neymar | Momo | Gareth +| Titi | Bruyne | Kylian +| Leo | Sally | Harry | + From 8840a96d07cf8b8fa6f654c5ea0f62c0381f9184 Mon Sep 17 00:00:00 2001 From: jordyhers Date: Sat, 28 Oct 2023 09:35:55 +0200 Subject: [PATCH 16/23] fix(#154): REFACTOR BACKGROUND NOTIFICATION service --- .idea/libraries/Flutter_Plugins.xml | 4 +- android/app/build.gradle | 2 +- android/app/src/main/AndroidManifest.xml | 1 + android/build.gradle | 3 - lib/app/config/android_config.dart | 35 -------- lib/app/features/child_side/child_page.dart | 1 - .../features/child_side/set_child_page.dart | 13 +-- lib/app/features/parent_side/parent_page.dart | 2 +- lib/main_development.dart | 9 +- lib/main_production.dart | 3 +- lib/main_staging.dart | 3 +- lib/services/api_path.dart | 1 + lib/services/database.dart | 23 +++-- lib/services/geo_locator_service.dart | 1 + lib/services/notification_service.dart | 89 +++++++++++++++---- pubspec.lock | 40 +++++++-- pubspec.yaml | 2 +- 17 files changed, 141 insertions(+), 91 deletions(-) diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index fcc3018..bf0c95e 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -58,7 +58,9 @@ - + + + diff --git a/android/app/build.gradle b/android/app/build.gradle index e224b11..9408c2d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -36,7 +36,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 33 + compileSdkVersion 34 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 90183ad..f9e0506 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -14,6 +14,7 @@ + backgroundFetchHeadlessTask(HeadlessTask task) async { - final taskId = task.taskId; - final isTimeout = task.timeout; - - JHLogger.$.e('[BackgroundFetch] Headless event received.'); - - if (isTimeout) { - JHLogger.$.e('[BackgroundFetch] Headless task timed-out: $taskId'); - BackgroundFetch.finish(taskId); - return; - } -} - -Future configureBackgroundFetch() async { - await BackgroundFetch.configure( - BackgroundFetchConfig( - minimumFetchInterval: 1, - stopOnTerminate: false, - enableHeadless: true, - requiresBatteryNotLow: false, - requiresCharging: false, - requiresStorageNotLow: false, - requiresDeviceIdle: false, - requiredNetworkType: NetworkType.NONE, - ), - backgroundFetchHeadlessTask, - ).then((int status) { - JHLogger.$.e('[BackgroundFetch] Headless task timed-out- $status'); - }).catchError((Object e) { - JHLogger.$.d('[BackgroundFetch] configure ERROR: $e'); - }); -} diff --git a/lib/app/features/child_side/child_page.dart b/lib/app/features/child_side/child_page.dart index 3e06c4e..ac42efb 100644 --- a/lib/app/features/child_side/child_page.dart +++ b/lib/app/features/child_side/child_page.dart @@ -70,7 +70,6 @@ class _ChildPageState extends State with WidgetsBindingObserver { @override void initState() { super.initState(); - WidgetsBinding.instance.addObserver(this); } diff --git a/lib/app/features/child_side/set_child_page.dart b/lib/app/features/child_side/set_child_page.dart index c16416b..19de91a 100644 --- a/lib/app/features/child_side/set_child_page.dart +++ b/lib/app/features/child_side/set_child_page.dart @@ -56,26 +56,27 @@ class _SetChildPageState extends State { } Future _submit(String name, String key, BuildContext context) async { - final database = Provider.of(context, listen: false); + final databaseStore = Provider.of(context, listen: false); final geo = Provider.of(context, listen: false); - final apps = Provider.of(context, listen: false); + final appUsage = Provider.of(context, listen: false); final position = await geo.getInitialLocation(); final battery = await Battery().batteryLevel; + try { - final response = await database.getUserCurrentChild( + final response = await databaseStore.getUserCurrentChild( key, - apps, + appUsage, GeoPoint(position.latitude, position.longitude), battery: battery.toString(), ); - JHLogger.$.d('RESPONSE : $response'); + try { if (mounted) { await Navigator.of(context).pushReplacement( MaterialPageRoute( fullscreenDialog: true, builder: (context) => - ChildPage.create(context, database, response), + ChildPage.create(context, databaseStore, response), ), ); } diff --git a/lib/app/features/parent_side/parent_page.dart b/lib/app/features/parent_side/parent_page.dart index 60eb362..906b712 100644 --- a/lib/app/features/parent_side/parent_page.dart +++ b/lib/app/features/parent_side/parent_page.dart @@ -128,7 +128,7 @@ class _ParentPageState extends State Widget _buildNotificationPage(AuthBase auth) { return Provider( - create: (_) => NotificationService(), + create: (context) => NotificationService(), builder: (context, __) { return NotificationPage.create(context, auth); }, diff --git a/lib/main_development.dart b/lib/main_development.dart index 8e4f6dc..5edda09 100644 --- a/lib/main_development.dart +++ b/lib/main_development.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:provider/provider.dart'; import 'package:times_up_flutter/app/app.dart'; -import 'package:times_up_flutter/app/config/android_config.dart'; import 'package:times_up_flutter/bootstrap.dart'; import 'package:times_up_flutter/firebase_options_dev.dart'; import 'package:times_up_flutter/services/app_info_service.dart'; @@ -18,12 +17,12 @@ import 'package:times_up_flutter/theme/theme_notifier.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - final packageInfo = await PackageInfo.fromPlatform(); + late final packageInfo; await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ).whenComplete(() async { + packageInfo = await PackageInfo.fromPlatform(); await _notificationServiceListener(); - await _backgroundListener(); }); await bootstrap( @@ -53,10 +52,6 @@ Future main() async { ); } -Future _backgroundListener() async { - await configureBackgroundFetch(); -} - Future _notificationServiceListener() async { final notificationService = NotificationService(); await notificationService.initialize().whenComplete( diff --git a/lib/main_production.dart b/lib/main_production.dart index 36c7e11..6ddecb9 100644 --- a/lib/main_production.dart +++ b/lib/main_production.dart @@ -17,10 +17,11 @@ import 'package:times_up_flutter/theme/theme_notifier.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - PackageInfo packageInfo = await PackageInfo.fromPlatform(); + late final packageInfo; await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ).whenComplete(() async { + packageInfo = await PackageInfo.fromPlatform(); await _notificationServiceListener(); }); diff --git a/lib/main_staging.dart b/lib/main_staging.dart index 287672b..5edda09 100644 --- a/lib/main_staging.dart +++ b/lib/main_staging.dart @@ -17,10 +17,11 @@ import 'package:times_up_flutter/theme/theme_notifier.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - PackageInfo packageInfo = await PackageInfo.fromPlatform(); + late final packageInfo; await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ).whenComplete(() async { + packageInfo = await PackageInfo.fromPlatform(); await _notificationServiceListener(); }); diff --git a/lib/services/api_path.dart b/lib/services/api_path.dart index 3279955..9b2f502 100644 --- a/lib/services/api_path.dart +++ b/lib/services/api_path.dart @@ -11,5 +11,6 @@ class APIPath { 'users/$uid/notifications/'; static String mail() => 'mail/'; + static String deviceToken() => 'DeviceTokens/'; } diff --git a/lib/services/database.dart b/lib/services/database.dart index 5eacf87..4be69fc 100644 --- a/lib/services/database.dart +++ b/lib/services/database.dart @@ -11,6 +11,8 @@ import 'package:times_up_flutter/utils/constants.dart'; import 'package:times_up_flutter/widgets/show_logger.dart'; abstract class Database { + ChildModel? get currentChild; + Future setChild(ChildModel model); Future updateChild(ChildModel model); @@ -46,10 +48,11 @@ abstract class Database { } class FireStoreDatabase implements Database { - FireStoreDatabase({ - required this.uid, - required this.auth, - }) { + factory FireStoreDatabase({required String uid, required AuthBase auth}) { + return _singleton ??= FireStoreDatabase._internal(uid, auth); + } + + FireStoreDatabase._internal(this.uid, this.auth) { if (auth.isFirstLogin) { sendEmail( email: EmailModel( @@ -57,19 +60,20 @@ class FireStoreDatabase implements Database { subject: EmailConstants.subject, text: EmailConstants.text, html: EmailConstants.html( - auth.currentUser!.displayName ?? auth.currentUser!.email!, - ), + auth.currentUser!.displayName ?? auth.currentUser!.email!), ), ).then((value) => auth.setFirstLogin(isFirstLogin: false)); } } - + static FireStoreDatabase? _singleton; + GeoLocatorService geo = GeoLocatorService(); final String uid; final AuthBase auth; ChildModel? _child; final _service = FireStoreService.instance; - GeoLocatorService geo = GeoLocatorService(); + @override + ChildModel? get currentChild => _child; @override Future setChild(ChildModel model) => _service.setData( @@ -150,7 +154,7 @@ class FireStoreDatabase implements Database { ) async { await apps.getAppUsageService(); - final point = await geo.getInitialLocation(); + final point = await geo.getCurrentLocation.last; final currentLocation = GeoPoint(point.latitude, point.longitude); _child = ChildModel( @@ -165,6 +169,7 @@ class FireStoreDatabase implements Database { ); await updateChild(_child!); + JHLogger.$.e('Child Updated : $_child'); } @override diff --git a/lib/services/geo_locator_service.dart b/lib/services/geo_locator_service.dart index 862b2f5..c5e87d5 100644 --- a/lib/services/geo_locator_service.dart +++ b/lib/services/geo_locator_service.dart @@ -15,6 +15,7 @@ class GeoLocatorService { Future getInitialLocation() async { permission = await Geolocator.requestPermission(); + if (permission == LocationPermission.denied) { return Future.error('Location permissions are denied'); } diff --git a/lib/services/notification_service.dart b/lib/services/notification_service.dart index 39c0161..cde4f92 100644 --- a/lib/services/notification_service.dart +++ b/lib/services/notification_service.dart @@ -1,18 +1,59 @@ // ignore_for_file: avoid_dynamic_calls +import 'dart:async'; +import 'dart:ui'; + import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_background_service/flutter_background_service.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:times_up_flutter/widgets/show_logger.dart'; +const notificationChannelId = 'high_importance_channel'; +const notificationChannelTitle = 'High Importance Notifications'; +const notificationId = 800; + const AndroidNotificationChannel channel = AndroidNotificationChannel( - 'high_importance_channel', // id - 'High Importance Notifications', // title + notificationChannelId, + notificationChannelTitle, description: 'This channel is used for important notifications.', - // description importance: Importance.max, ); +@pragma('vm:entry-point') +Future onStart(ServiceInstance service) async { + DartPluginRegistrant.ensureInitialized(); + service.on('stopService').listen((event) { + service.stopSelf(); + }); + Timer.periodic(const Duration(minutes: 15), (timer) async { + // TODO(JORDY): IMPLEMENT DATA UPDATE HERE + // final databaseStore = Provider.of(context!, listen: false); + // final appUsage = Provider.of(context, listen: false); + // JHLogger.$.e(' NOT READy '); + // if (databaseStore.currentChild != null) { + // await databaseStore.liveUpdateChild( + // databaseStore.currentChild!, + // appUsage, + // ); + // } + await NotificationService.flutterLocalNotificationsPlugin.show( + notificationId, + 'Times Up - Monitoring', + 'Tracking App Usage and live location', + const NotificationDetails( + android: AndroidNotificationDetails( + notificationChannelId, + notificationChannelTitle, + icon: 'parental_launch', + ongoing: true, + importance: Importance.max, + ), + ), + ); + }); +} + class NotificationService { factory NotificationService() { return _singleton; @@ -22,21 +63,38 @@ class NotificationService { static final NotificationService _singleton = NotificationService._internal(); // Here the set up for cloud Messaging Android is being configured - final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + static final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - // The LocalPlugin method configures the android channel - Future localPlugin() async => await flutterLocalNotificationsPlugin - .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() - ?.createNotificationChannel(channel); - Future initialize() async { - await flutterLocalNotificationsPlugin.initialize( - const InitializationSettings( - android: AndroidInitializationSettings('@drawable/parental_launch'), - ), - ); + try { + final service = FlutterBackgroundService(); + await flutterLocalNotificationsPlugin + .initialize( + const InitializationSettings( + android: AndroidInitializationSettings('@drawable/parental_launch'), + ), + ) + .then((value) async { + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannel(channel); + + await service.configure( + iosConfiguration: IosConfiguration(), + androidConfiguration: AndroidConfiguration( + onStart: onStart, + isForegroundMode: true, + initialNotificationTitle: 'Times Up Flutter Launched', + initialNotificationContent: 'The app is tracking metadata', + foregroundServiceNotificationId: notificationId, + ), + ); + }); + } catch (e) { + JHLogger.$.e(e); + } } // Create a new instance of Firebase Messaging @@ -46,7 +104,6 @@ class NotificationService { final androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>(); - await androidImplementation?.requestPermission(); } diff --git a/pubspec.lock b/pubspec.lock index b826d01..4aadf5d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -57,14 +57,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" - background_fetch: - dependency: "direct main" - description: - name: background_fetch - sha256: f70b28a0f7a3156195e9742229696f004ea3bf10f74039b7bf4c78a74fbda8a4 - url: "https://pub.dev" - source: hosted - version: "1.2.1" battery_plus: dependency: "direct main" description: @@ -502,6 +494,38 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_background_service: + dependency: "direct main" + description: + name: flutter_background_service + sha256: "7b18ac89f88e521a44e9da8fcaa768a59b7c2cfad9f41bf3fcc6cf673032e33e" + url: "https://pub.dev" + source: hosted + version: "5.0.2" + flutter_background_service_android: + dependency: transitive + description: + name: flutter_background_service_android + sha256: "4998b3d191a04f36f720eff69d3905f384b91e1f92b3dd74aca4ffb5670f38dc" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + flutter_background_service_ios: + dependency: transitive + description: + name: flutter_background_service_ios + sha256: ab73657535876e16abc89e40f924df3e92ad3dee83f64d187081417e824709ed + url: "https://pub.dev" + source: hosted + version: "5.0.0" + flutter_background_service_platform_interface: + dependency: transitive + description: + name: flutter_background_service_platform_interface + sha256: cd5720ff5b051d551a4734fae16683aace779bd0425e8d3f15d84a0cdcc2d8d9 + url: "https://pub.dev" + source: hosted + version: "5.0.0" flutter_bloc: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 3342930..1d60b15 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,7 +40,7 @@ dependencies: # Notification Packages: firebase_messaging: ^14.4.0 flutter_local_notifications: ^14.0.0-dev.2 - background_fetch: ^1.2.1 + flutter_background_service: ^5.0.2 # Utility Packages: intl: any From 4c7c9b1c19508f98ad684858368e626fe62247a5 Mon Sep 17 00:00:00 2001 From: jordyhers Date: Tue, 31 Oct 2023 14:24:09 +0100 Subject: [PATCH 17/23] fix(#154): fix linting --- lib/services/database.dart | 3 ++- lib/services/firestore_service.dart | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/services/database.dart b/lib/services/database.dart index 4be69fc..e196374 100644 --- a/lib/services/database.dart +++ b/lib/services/database.dart @@ -60,7 +60,8 @@ class FireStoreDatabase implements Database { subject: EmailConstants.subject, text: EmailConstants.text, html: EmailConstants.html( - auth.currentUser!.displayName ?? auth.currentUser!.email!), + auth.currentUser!.displayName ?? auth.currentUser!.email!, + ), ), ).then((value) => auth.setFirstLogin(isFirstLogin: false)); } diff --git a/lib/services/firestore_service.dart b/lib/services/firestore_service.dart index bb0ecea..3f8629a 100644 --- a/lib/services/firestore_service.dart +++ b/lib/services/firestore_service.dart @@ -2,9 +2,7 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_storage/firebase_storage.dart'; -import 'package:flutter/foundation.dart'; import 'package:times_up_flutter/models/notification_model/notification_model.dart'; - import 'package:times_up_flutter/widgets/show_logger.dart'; typedef QueryBuilder = T Function(Map data); From d4f8596d7945e19bee30e552b97954d8a3ebc758 Mon Sep 17 00:00:00 2001 From: bhoomikshetty Date: Wed, 1 Nov 2023 00:16:16 +0530 Subject: [PATCH 18/23] feat(#226) : Implement the possibility to `reset password` in `forgot password` section --- .../features/sign_in/email_sign_in_bloc.dart | 9 ++++ .../email_sign_in_form_bloc_based.dart | 46 +++++++++++++++++++ .../features/sign_in/email_sign_in_model.dart | 4 ++ lib/services/auth.dart | 12 +++++ 4 files changed, 71 insertions(+) diff --git a/lib/app/features/sign_in/email_sign_in_bloc.dart b/lib/app/features/sign_in/email_sign_in_bloc.dart index 144e29b..6df238a 100644 --- a/lib/app/features/sign_in/email_sign_in_bloc.dart +++ b/lib/app/features/sign_in/email_sign_in_bloc.dart @@ -42,6 +42,15 @@ class EmailSignInBloc { } } + + Future forgotPassword(String email) async{ + try { + return await auth.forgotPassword(email); + } catch (e) { + rethrow; + } + } + void toggleFormType() { final formType = _model.formType == EmailSignInFormType.signIn ? EmailSignInFormType.register diff --git a/lib/app/features/sign_in/email_sign_in_form_bloc_based.dart b/lib/app/features/sign_in/email_sign_in_form_bloc_based.dart index 9ad8546..bda0fad 100644 --- a/lib/app/features/sign_in/email_sign_in_form_bloc_based.dart +++ b/lib/app/features/sign_in/email_sign_in_form_bloc_based.dart @@ -8,6 +8,7 @@ import 'package:times_up_flutter/app/features/sign_in/email_sign_in_model.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/widgets/jh_form_submit_button.dart'; +import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; class EmailSignInFormBlocBased extends StatefulWidget { @@ -74,6 +75,37 @@ class _EmailSignInFormBlocBasedState extends State { } } + Future? _forgotPassword(EmailSignInModel model, String email) async { + try { + if (model.canResetPassword) { + final emailSent = await widget.bloc.forgotPassword(email); + if (emailSent) { + // ignore: use_build_context_synchronously + await showAlertDialog( + context, + title: 'Password reset email sent to $email', + content: 'Please check your email', + defaultActionText: 'OK', + ); + } else { + // ignore: use_build_context_synchronously + await showAlertDialog( + context, + title: 'Password reset failed', + content: 'There was some issue', + defaultActionText: 'OK', + ); + } + } + } on FirebaseAuthException catch (e) { + await showExceptionAlertDialog( + context, + title: model.signInFailedText, + exception: e, + ); + } + } + void _emailEditingComplete(EmailSignInModel model) { final newFocus = model.emailValidator.isValid(model.email) ? _passwordFocusNode @@ -106,6 +138,8 @@ class _EmailSignInFormBlocBasedState extends State { const SizedBox(height: 8), _buildPasswordTextField(model), const SizedBox(height: 8), + _buildForgotPassword(model), + const SizedBox(height: 8), FormSubmitButton( onPressed: () => model.canSubmitRegister || model.canSubmitSignIn ? _submit(model) @@ -203,6 +237,18 @@ class _EmailSignInFormBlocBasedState extends State { ); } + Widget _buildForgotPassword(EmailSignInModel model) { + return GestureDetector( + onTap: () => _forgotPassword(model, _emailController.text), + child: Container( + margin: const EdgeInsets.symmetric(vertical: 8), + width: double.infinity, + alignment: Alignment.centerRight, + child: const Text('Forgot Password?'), + ), + ); + } + @override Widget build(BuildContext context) { return SingleChildScrollView( diff --git a/lib/app/features/sign_in/email_sign_in_model.dart b/lib/app/features/sign_in/email_sign_in_model.dart index 30d4608..bbcc2bb 100644 --- a/lib/app/features/sign_in/email_sign_in_model.dart +++ b/lib/app/features/sign_in/email_sign_in_model.dart @@ -32,6 +32,10 @@ class EmailSignInModel with EmailAndPasswordValidators { !isLoading; } + bool get canResetPassword { + return emailValidator.isValid(email); + } + bool get canSubmitRegister { return emailValidator.isValid(email) && passwordValidator.isValid(password) && diff --git a/lib/services/auth.dart b/lib/services/auth.dart index d977b35..fdc202e 100644 --- a/lib/services/auth.dart +++ b/lib/services/auth.dart @@ -33,6 +33,8 @@ abstract class AuthBase { String name, String surname, ); + + Future forgotPassword(String email); } class Auth implements AuthBase { @@ -186,4 +188,14 @@ class Auth implements AuthBase { _isFirstLogin = false; await _firebaseAuth.signOut(); } + + @override + Future forgotPassword(String email) async { + try { + await _firebaseAuth.sendPasswordResetEmail(email: email); + return true; + } catch (e) { + return false; + } + } } From a5f700ee4d382d2c427f724b39993d6ed3af980f Mon Sep 17 00:00:00 2001 From: jordyhers Date: Wed, 1 Nov 2023 09:14:29 +0100 Subject: [PATCH 19/23] chore(#226): fix padding --- .../sign_in/email_sign_in_form_bloc_based.dart | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/app/features/sign_in/email_sign_in_form_bloc_based.dart b/lib/app/features/sign_in/email_sign_in_form_bloc_based.dart index bda0fad..99ff696 100644 --- a/lib/app/features/sign_in/email_sign_in_form_bloc_based.dart +++ b/lib/app/features/sign_in/email_sign_in_form_bloc_based.dart @@ -7,6 +7,7 @@ import 'package:times_up_flutter/app/features/sign_in/email_sign_in_bloc.dart'; import 'package:times_up_flutter/app/features/sign_in/email_sign_in_model.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; import 'package:times_up_flutter/widgets/jh_form_submit_button.dart'; import 'package:times_up_flutter/widgets/show_alert_dialog.dart'; import 'package:times_up_flutter/widgets/show_exeption_alert.dart'; @@ -137,8 +138,9 @@ class _EmailSignInFormBlocBasedState extends State { _buildEmailTextField(model), const SizedBox(height: 8), _buildPasswordTextField(model), - const SizedBox(height: 8), - _buildForgotPassword(model), + const SizedBox(height: 16), + if (model.formType == EmailSignInFormType.signIn) + _buildForgotPassword(model), const SizedBox(height: 8), FormSubmitButton( onPressed: () => model.canSubmitRegister || model.canSubmitSignIn @@ -244,7 +246,10 @@ class _EmailSignInFormBlocBasedState extends State { margin: const EdgeInsets.symmetric(vertical: 8), width: double.infinity, alignment: Alignment.centerRight, - child: const Text('Forgot Password?'), + child: JHDisplayText( + text: 'Forgot Password ?', + style: TextStyle(color: Colors.white.withOpacity(0.6), fontSize: 10), + ), ), ); } From 0167cb4d5ce5ec63e14da678c3f4d0bf4a872234 Mon Sep 17 00:00:00 2001 From: jordyhers Date: Wed, 8 Nov 2023 13:47:21 +0100 Subject: [PATCH 20/23] chore(#226): refactor and clean change theme mode. --- lib/app/features/landing_page.dart | 2 +- .../parent_side/child_details_page.dart | 4 ++- .../features/parent_side/language_page.dart | 0 lib/app/features/parent_side/parent_page.dart | 4 +-- lib/app/features/splash/splash_screen.dart | 9 +++--- lib/app/helpers/parsing_extension.dart | 3 +- lib/app/screen_controller.dart | 2 +- lib/main_development.dart | 2 +- lib/services/app_usage_service.dart | 2 +- lib/services/shared_preferences.dart | 28 +++++++++++++------ lib/theme/theme_notifier.dart | 7 +++++ 11 files changed, 41 insertions(+), 22 deletions(-) create mode 100644 lib/app/features/parent_side/language_page.dart diff --git a/lib/app/features/landing_page.dart b/lib/app/features/landing_page.dart index 2cc8641..dc5fe72 100644 --- a/lib/app/features/landing_page.dart +++ b/lib/app/features/landing_page.dart @@ -32,7 +32,7 @@ class _LandingPageState extends State { } Future _setFlagParentOrChild() async { - final isParent = await SharedPreference().getParentOrChild(); + final isParent = await CacheService.getParentOrChild(); setState(() { isParent ? _side = AppSide.parent : _side = AppSide.child; }); diff --git a/lib/app/features/parent_side/child_details_page.dart b/lib/app/features/parent_side/child_details_page.dart index 13f491a..21340a6 100644 --- a/lib/app/features/parent_side/child_details_page.dart +++ b/lib/app/features/parent_side/child_details_page.dart @@ -379,7 +379,9 @@ class _AppUsedList extends StatelessWidget { padding: EdgeInsets.zero, physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, - itemCount: (model.appsUsageModel.length * 0.20).toInt(), + itemCount: model.appsUsageModel.length > 5 + ? 5 + : (model.appsUsageModel.length * 0.20).toInt(), itemBuilder: (context, index) { return Column( mainAxisSize: MainAxisSize.min, diff --git a/lib/app/features/parent_side/language_page.dart b/lib/app/features/parent_side/language_page.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/app/features/parent_side/parent_page.dart b/lib/app/features/parent_side/parent_page.dart index 906b712..587effa 100644 --- a/lib/app/features/parent_side/parent_page.dart +++ b/lib/app/features/parent_side/parent_page.dart @@ -342,10 +342,10 @@ class _ParentPageState extends State } Future _setShowCaseView() async { - final isVisited = await SharedPreference().getDisplayShowCase(); + final isVisited = await CacheService.getDisplayShowCase(); setState(() { _isShowCaseActivated = isVisited; - SharedPreference().setDisplayShowCase(); + CacheService.setDisplayShowCase(); }); if (!_isShowCaseActivated) { diff --git a/lib/app/features/splash/splash_screen.dart b/lib/app/features/splash/splash_screen.dart index d410674..1c3ba30 100644 --- a/lib/app/features/splash/splash_screen.dart +++ b/lib/app/features/splash/splash_screen.dart @@ -59,8 +59,8 @@ class _SplashScreenState extends State { backgroundColor: Theme.of(context).primaryColor, title: 'Parent device'.toUpperCase(), onPress: () { - SharedPreference().setVisitingFlag(); - SharedPreference().setParentDevice(); + CacheService.setVisitingFlag(); + CacheService.setParentDevice(); Navigator.of(context).pushReplacement( CupertinoPageRoute( builder: (context) => const LandingPage(), @@ -73,9 +73,8 @@ class _SplashScreenState extends State { backgroundColor: CustomColors.greenPrimary, title: 'Child device'.toUpperCase(), onPress: () { - SharedPreference().setVisitingFlag(); - SharedPreference().setChildDevice(); - + CacheService.setVisitingFlag(); + CacheService.setChildDevice(); Navigator.of(context).pushReplacement( CupertinoPageRoute( builder: (context) => const LandingPage(), diff --git a/lib/app/helpers/parsing_extension.dart b/lib/app/helpers/parsing_extension.dart index 2d90ad0..c0d7183 100644 --- a/lib/app/helpers/parsing_extension.dart +++ b/lib/app/helpers/parsing_extension.dart @@ -1,7 +1,6 @@ import 'dart:math'; import 'package:intl/intl.dart'; -import 'package:times_up_flutter/widgets/show_logger.dart'; extension ParseResult on String { String t() { @@ -136,7 +135,7 @@ double calculatePercentage(Duration duration) { final totalMilliseconds = totalDuration.inMilliseconds; final res = (milliseconds / totalMilliseconds) * 100; - JHLogger.$.d(parsedDuration); + //JHLogger.$.d(parsedDuration); return res; } diff --git a/lib/app/screen_controller.dart b/lib/app/screen_controller.dart index 6e3cc3b..2166dad 100644 --- a/lib/app/screen_controller.dart +++ b/lib/app/screen_controller.dart @@ -25,7 +25,7 @@ class _ScreensControllerState extends State { bool? _hasVisited; Future _setFlagValue() async { - final isVisited = await SharedPreference().getVisitingFlag(); + final isVisited = await CacheService.getVisitingFlag(); setState(() { _hasVisited = isVisited; }); diff --git a/lib/main_development.dart b/lib/main_development.dart index 5edda09..e949bba 100644 --- a/lib/main_development.dart +++ b/lib/main_development.dart @@ -43,7 +43,7 @@ Future main() async { ..getInitialConnectionStatus(), ), ChangeNotifierProvider( - create: (context) => ThemeNotifier()..toggleTheme()), + create: (context) => ThemeNotifier()..initThemeMode()), ChangeNotifierProvider( create: (context) => AppInfoService(packageInfo)), ], diff --git a/lib/services/app_usage_service.dart b/lib/services/app_usage_service.dart index 7ec04e6..642f84b 100644 --- a/lib/services/app_usage_service.dart +++ b/lib/services/app_usage_service.dart @@ -51,7 +51,7 @@ class AppUsageService implements AppService { } } final averageDuration = getMedian(durations); - JHLogger.$.e(averageDuration); + // JHLogger.$.e(averageDuration); _averageDuration = averageDuration; return averageDuration; } diff --git a/lib/services/shared_preferences.dart b/lib/services/shared_preferences.dart index f74b755..0355921 100644 --- a/lib/services/shared_preferences.dart +++ b/lib/services/shared_preferences.dart @@ -1,42 +1,54 @@ import 'package:shared_preferences/shared_preferences.dart'; -class SharedPreference { - Future getVisitingFlag() async { +class CacheService { + static Future getVisitingFlag() async { final preferences = await SharedPreferences.getInstance(); final alreadyVisited = preferences.getBool('alreadyVisited') ?? false; return alreadyVisited; } - Future getParentOrChild() async { + static Future getParentOrChild() async { final preferences = await SharedPreferences.getInstance(); final isParent = preferences.getBool('isParent') ?? true; return isParent; } - Future getDisplayShowCase() async { + static Future getDisplayShowCase() async { final preferences = await SharedPreferences.getInstance(); final displayShowCase = preferences.getBool('displayShowCase') ?? false; return displayShowCase; } - Future setVisitingFlag() async { + static Future getThemeMode() async { + final preferences = await SharedPreferences.getInstance(); + final darkMode = preferences.getBool('isDarkMode') ?? false; + return darkMode; + } + + static Future setVisitingFlag() async { final preferences = await SharedPreferences.getInstance(); await preferences.setBool('alreadyVisited', true); } - Future setParentDevice() async { + static Future setParentDevice() async { final preferences = await SharedPreferences.getInstance(); await preferences.setBool('isParent', true); } - Future setChildDevice() async { + static Future setChildDevice() async { final preferences = await SharedPreferences.getInstance(); await preferences.setBool('isParent', false); } - Future setDisplayShowCase() async { + static Future setDisplayShowCase() async { final preferences = await SharedPreferences.getInstance(); final status = await preferences.setBool('displayShowCase', true); return status; } + + static Future setTheDarkTheme({required bool value}) async { + final preferences = await SharedPreferences.getInstance(); + final status = await preferences.setBool('isDarkMode', value); + return status; + } } diff --git a/lib/theme/theme_notifier.dart b/lib/theme/theme_notifier.dart index 008b6b5..5d7c155 100644 --- a/lib/theme/theme_notifier.dart +++ b/lib/theme/theme_notifier.dart @@ -1,12 +1,19 @@ import 'package:flutter/material.dart'; +import 'package:times_up_flutter/services/shared_preferences.dart'; class ThemeNotifier extends ChangeNotifier { bool _isDarkMode = false; bool get isDarkMode => _isDarkMode; + Future initThemeMode() async { + _isDarkMode = await CacheService.getThemeMode(); + notifyListeners(); + } + void toggleTheme() { _isDarkMode = !_isDarkMode; + CacheService.setTheDarkTheme(value: _isDarkMode); notifyListeners(); } } From 9a3b4967dcad5cfda86b0c9042758dd35f8e6b49 Mon Sep 17 00:00:00 2001 From: jordyhers Date: Wed, 8 Nov 2023 15:03:01 +0100 Subject: [PATCH 21/23] chore(#43): refactor to implement change language. --- lib/app/app.dart | 2 + .../language/language_notififier.dart | 45 ++++++ .../parent_side/language/language_page.dart | 129 ++++++++++++++++++ .../features/parent_side/language_page.dart | 0 .../features/parent_side/setting_page.dart | 8 +- lib/main_development.dart | 3 + lib/main_production.dart | 4 +- lib/main_staging.dart | 4 +- lib/utils/constants.dart | 1 - 9 files changed, 189 insertions(+), 7 deletions(-) create mode 100644 lib/app/features/parent_side/language/language_notififier.dart create mode 100644 lib/app/features/parent_side/language/language_page.dart delete mode 100644 lib/app/features/parent_side/language_page.dart diff --git a/lib/app/app.dart b/lib/app/app.dart index 8f57254..6c5705c 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; +import 'package:times_up_flutter/app/features/parent_side/language/language_notififier.dart'; import 'package:times_up_flutter/app/screen_controller.dart'; import 'package:times_up_flutter/l10n/l10n.dart'; import 'package:times_up_flutter/theme/theme.dart'; @@ -19,6 +20,7 @@ class TimesUpApp extends StatelessWidget { return MaterialApp( debugShowCheckedModeBanner: false, + locale: Provider.of(context).locale, title: Strings.appName, theme: AppTheme.lightTheme, darkTheme: AppTheme.darkTheme, diff --git a/lib/app/features/parent_side/language/language_notififier.dart b/lib/app/features/parent_side/language/language_notififier.dart new file mode 100644 index 0000000..fc86286 --- /dev/null +++ b/lib/app/features/parent_side/language/language_notififier.dart @@ -0,0 +1,45 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; + +class LanguageNotifier extends ChangeNotifier { + late String _selectedLanguage = '🇺🇸 English󠁢'; + late Locale _locale = const Locale('en'); + + String get selectedLanguage => _selectedLanguage; + Locale get locale => _locale; + + List languages = [ + '🇫🇷 Français󠁢', + '🇪🇸 Español', + '🇹🇷 Turkish', + '🇩🇪 Deutsch', + ]; + + void selectLanguage(String language) { + languages.insert(languages.indexOf(language), _selectedLanguage); + _selectedLanguage = language; + languages.removeWhere((element) => element == _selectedLanguage); + _locale = setLocale(_selectedLanguage); + HapticFeedback.heavyImpact(); + notifyListeners(); + } + + Locale setLocale(String selectedLanguage) { + switch (selectedLanguage) { + case '🇫🇷 Français󠁢': + return const Locale('fr'); + case '🇺🇸 English󠁢': + return const Locale('en'); + case '🇪🇸 Español': + return const Locale('es'); + case '🇹🇷 Turkish': + return const Locale('tr'); + case '🇩🇪 Deutsch󠁢': + return const Locale('de'); + default: + return const Locale('en'); + } + } +} diff --git a/lib/app/features/parent_side/language/language_page.dart b/lib/app/features/parent_side/language/language_page.dart new file mode 100644 index 0000000..7fe68d5 --- /dev/null +++ b/lib/app/features/parent_side/language/language_page.dart @@ -0,0 +1,129 @@ +// ignore_for_file: library_private_types_in_public_api + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:times_up_flutter/app/features/parent_side/language/language_notififier.dart'; +import 'package:times_up_flutter/services/auth.dart'; +import 'package:times_up_flutter/theme/theme.dart'; +import 'package:times_up_flutter/widgets/jh_display_text.dart'; + +class LanguagePage extends StatefulWidget { + const LanguagePage({ + required this.auth, + required this.languageModel, + Key? key, + }) : super(key: key); + final AuthBase auth; + final LanguageNotifier languageModel; + + static Widget create( + BuildContext context, + AuthBase auth, + ) { + return Consumer( + builder: (BuildContext context, value, Widget? child) => LanguagePage( + auth: auth, + languageModel: value, + ), + ); + } + + @override + _LanguagePageState createState() => _LanguagePageState(); +} + +class _LanguagePageState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + final color = Theme.of(context).brightness == Brightness.dark + ? Colors.white + : CustomColors.indigoDark; + + return Scaffold( + body: NestedScrollView( + headerSliverBuilder: (BuildContext context, value) { + return [ + SliverAppBar( + elevation: 0.5, + shadowColor: CustomColors.indigoLight, + iconTheme: IconThemeData(color: color), + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + expandedHeight: 50, + pinned: true, + floating: true, + ) + ]; + }, + body: ScrollConfiguration( + behavior: const ScrollBehavior().copyWith(overscroll: false), + child: CustomScrollView( + slivers: [ + SliverToBoxAdapter( + child: JHDisplayText( + text: 'Languages', + style: TextStyle( + color: color, + fontWeight: FontWeight.w700, + ), + fontSize: 32, + maxFontSize: 34, + ).hP16, + ), + const SliverPadding(padding: EdgeInsets.only(top: 50)), + SliverToBoxAdapter( + child: Card( + margin: const EdgeInsets.symmetric(horizontal: 50), + color: CustomColors.indigoLight, + child: Center( + child: SizedBox( + height: 60, + child: Center( + child: JHDisplayText( + text: widget.languageModel.selectedLanguage, + style: TextStyles.title, + ), + ), + ), + ), + ), + ), + SliverList( + delegate: SliverChildListDelegate([ + SingleChildScrollView( + child: SizedBox( + height: 2000, + child: ListView.separated( + itemCount: 4, + itemBuilder: (builder, index) => GestureDetector( + onTap: () => widget.languageModel.selectLanguage( + widget.languageModel.languages[index], + ), + child: JHDisplayText( + text: widget.languageModel.languages[index], + style: TextStyles.title, + ).p(8), + ), + separatorBuilder: (BuildContext context, int index) => + const Divider( + thickness: 1, + indent: 20, + endIndent: 20, + color: Colors.grey, + ).p4, + ), + ), + ), + ]), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/app/features/parent_side/language_page.dart b/lib/app/features/parent_side/language_page.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/app/features/parent_side/setting_page.dart b/lib/app/features/parent_side/setting_page.dart index eb0e021..5bf8f66 100644 --- a/lib/app/features/parent_side/setting_page.dart +++ b/lib/app/features/parent_side/setting_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; import 'package:provider/provider.dart'; +import 'package:times_up_flutter/app/features/parent_side/language/language_page.dart'; import 'package:times_up_flutter/services/app_info_service.dart'; import 'package:times_up_flutter/services/auth.dart'; import 'package:times_up_flutter/theme/theme.dart'; @@ -95,10 +96,9 @@ class SettingsPage extends StatelessWidget { ).vTopP(12), ProfileListItem( icon: LineAwesomeIcons.language, - onPressed: () => showDialog( - context: context, - builder: (_) => const JHNoImplementationWidget(), - ), + onPressed: () => Navigator.of(context).push(MaterialPageRoute( + builder: (context) => LanguagePage.create(context, auth), + )), text: 'Change language', ), ProfileListItem( diff --git a/lib/main_development.dart b/lib/main_development.dart index e949bba..6327892 100644 --- a/lib/main_development.dart +++ b/lib/main_development.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:provider/provider.dart'; import 'package:times_up_flutter/app/app.dart'; +import 'package:times_up_flutter/app/features/parent_side/language/language_notififier.dart'; import 'package:times_up_flutter/bootstrap.dart'; import 'package:times_up_flutter/firebase_options_dev.dart'; import 'package:times_up_flutter/services/app_info_service.dart'; @@ -44,6 +45,8 @@ Future main() async { ), ChangeNotifierProvider( create: (context) => ThemeNotifier()..initThemeMode()), + ChangeNotifierProvider( + create: (context) => LanguageNotifier()), ChangeNotifierProvider( create: (context) => AppInfoService(packageInfo)), ], diff --git a/lib/main_production.dart b/lib/main_production.dart index 6ddecb9..93d9cf2 100644 --- a/lib/main_production.dart +++ b/lib/main_production.dart @@ -43,7 +43,9 @@ Future main() async { ..getInitialConnectionStatus(), ), ChangeNotifierProvider( - create: (context) => ThemeNotifier()..toggleTheme()), + create: (context) => ThemeNotifier()..initThemeMode()), + ChangeNotifierProvider( + create: (context) => LanguageNotifier()), ChangeNotifierProvider( create: (context) => AppInfoService(packageInfo)), ], diff --git a/lib/main_staging.dart b/lib/main_staging.dart index 5edda09..11fd5f8 100644 --- a/lib/main_staging.dart +++ b/lib/main_staging.dart @@ -43,7 +43,9 @@ Future main() async { ..getInitialConnectionStatus(), ), ChangeNotifierProvider( - create: (context) => ThemeNotifier()..toggleTheme()), + create: (context) => ThemeNotifier()..initThemeMode()), + ChangeNotifierProvider( + create: (context) => LanguageNotifier()), ChangeNotifierProvider( create: (context) => AppInfoService(packageInfo)), ], diff --git a/lib/utils/constants.dart b/lib/utils/constants.dart index eac0963..ad275c1 100644 --- a/lib/utils/constants.dart +++ b/lib/utils/constants.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; - import 'package:times_up_flutter/utils/app_strings.dart'; class Keys { From 4def68a9fdeeb3db83489b3fc07c0c7cf3707477 Mon Sep 17 00:00:00 2001 From: jordyhers Date: Wed, 8 Nov 2023 16:04:53 +0100 Subject: [PATCH 22/23] chore(#43): add more translations. --- .../language/language_notififier.dart | 29 +++++++++++++++++++ .../parent_side/language/language_page.dart | 2 +- .../features/parent_side/setting_page.dart | 8 +++-- lib/l10n/arb/app_de.arb | 23 ++++++++------- lib/l10n/arb/app_en.arb | 1 + lib/l10n/arb/app_es.arb | 3 +- lib/l10n/arb/app_fr.arb | 1 + lib/l10n/arb/app_tr.arb | 1 + lib/main_development.dart | 2 +- lib/services/shared_preferences.dart | 14 +++++++++ lib/theme/theme.dart | 4 +++ lib/widgets/jh_header.dart | 5 ++-- 12 files changed, 75 insertions(+), 18 deletions(-) diff --git a/lib/app/features/parent_side/language/language_notififier.dart b/lib/app/features/parent_side/language/language_notififier.dart index fc86286..0405e25 100644 --- a/lib/app/features/parent_side/language/language_notififier.dart +++ b/lib/app/features/parent_side/language/language_notififier.dart @@ -2,6 +2,7 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'package:times_up_flutter/services/shared_preferences.dart'; class LanguageNotifier extends ChangeNotifier { late String _selectedLanguage = '🇺🇸 English󠁢'; @@ -11,17 +12,45 @@ class LanguageNotifier extends ChangeNotifier { Locale get locale => _locale; List languages = [ + '🇺🇸 English󠁢', '🇫🇷 Français󠁢', '🇪🇸 Español', '🇹🇷 Turkish', '🇩🇪 Deutsch', ]; + Future initLocalization() async { + _locale = await CacheService.getLocale(); + switch (_locale.languageCode) { + case 'en': + _selectedLanguage = '🇺🇸 English󠁢'; + break; + case 'fr': + _selectedLanguage = '🇫🇷 Français󠁢'; + break; + case 'es': + _selectedLanguage = '🇪🇸 Español'; + break; + case 'de': + _selectedLanguage = '🇩🇪 Deutsch'; + break; + case 'tr': + _selectedLanguage = '🇹🇷 Turkish󠁢'; + break; + } + + languages + ..insert(languages.indexOf(_selectedLanguage), _selectedLanguage) + ..removeWhere((element) => element == _selectedLanguage); + notifyListeners(); + } + void selectLanguage(String language) { languages.insert(languages.indexOf(language), _selectedLanguage); _selectedLanguage = language; languages.removeWhere((element) => element == _selectedLanguage); _locale = setLocale(_selectedLanguage); + CacheService.setLocale(value: _locale); HapticFeedback.heavyImpact(); notifyListeners(); } diff --git a/lib/app/features/parent_side/language/language_page.dart b/lib/app/features/parent_side/language/language_page.dart index 7fe68d5..a56d237 100644 --- a/lib/app/features/parent_side/language/language_page.dart +++ b/lib/app/features/parent_side/language/language_page.dart @@ -96,7 +96,7 @@ class _LanguagePageState extends State { delegate: SliverChildListDelegate([ SingleChildScrollView( child: SizedBox( - height: 2000, + height: 1000, child: ListView.separated( itemCount: 4, itemBuilder: (builder, index) => GestureDetector( diff --git a/lib/app/features/parent_side/setting_page.dart b/lib/app/features/parent_side/setting_page.dart index 5bf8f66..bce1b73 100644 --- a/lib/app/features/parent_side/setting_page.dart +++ b/lib/app/features/parent_side/setting_page.dart @@ -96,9 +96,11 @@ class SettingsPage extends StatelessWidget { ).vTopP(12), ProfileListItem( icon: LineAwesomeIcons.language, - onPressed: () => Navigator.of(context).push(MaterialPageRoute( - builder: (context) => LanguagePage.create(context, auth), - )), + onPressed: () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => LanguagePage.create(context, auth), + ), + ), text: 'Change language', ), ProfileListItem( diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 69d1d0b..b3cb106 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -1,12 +1,15 @@ { - "@@locale": "de", - "welcome": "Wilkommen", - "changeTheSettingsHere": "Ändern Sie hier die Einstellungen", - "addNewChildHere": "Fügen Sie hier ein neues Kind hinzu", - "operationFailed": "Operation failed", - "enterThisCode": "Enter this code on the child's device", - "longPressToCopyOrDoubleTapToShare": "Long press to copy or double tap to share", - "enterThisCodeOnChildDevice": "Enter this code on child's device: ", - "sendNotificationToYourChildDevice": "Send notifications to your Child's device", - "copyText" : "Code Copied!" + "@@locale": "de", + "welcome": "Wilkommen", + "hello": "Hallo 👋", + "changeTheSettingsHere": "Ändern Sie hier die Einstellungen", + "addNewChildHere": "Fügen Sie hier ein neues Kind hinzu", + "operationFailed": "Operation failed", + "enterThisCode": "Enter this code on the child's device", + "longPressToCopyOrDoubleTapToShare": "Long press to copy or double tap to share", + "enterThisCodeOnChildDevice": "Enter this code on child's device: ", + "sendNotificationToYourChildDevice": "Send notifications to your Child's device", + "copyText" : "Code Copied!" + + } \ No newline at end of file diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 9aea62f..5dee837 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -1,6 +1,7 @@ { "@@locale": "en", "welcome": "Welcome", + "hello": "Hello 👋", "changeTheSettingsHere": "change the settings here", "addNewChildHere": "Add a new child here ", "operationFailed": "Operation failed", diff --git a/lib/l10n/arb/app_es.arb b/lib/l10n/arb/app_es.arb index 636b73d..8881d5f 100644 --- a/lib/l10n/arb/app_es.arb +++ b/lib/l10n/arb/app_es.arb @@ -1,6 +1,7 @@ { "@@locale": "es", - "welcome": "Hola !", + "welcome": "Bienvenido !", + "hello": "Hola 👋", "changeTheSettingsHere": "Cambiar la configuración aquí", "addNewChildHere": "Añadir un nuevo niño[a] aquí", "operationFailed": "Operation failed", diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index 5f7664f..711c389 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -1,6 +1,7 @@ { "@@locale": "fr", "welcome": "Bienvenue", + "hello": "Salut 👋", "changeTheSettingsHere": "Modifier les paramètres ici", "addNewChildHere": "Ajoute un enfant ici", "operationFailed": "Operation failed", diff --git a/lib/l10n/arb/app_tr.arb b/lib/l10n/arb/app_tr.arb index d39ae05..3c26bff 100644 --- a/lib/l10n/arb/app_tr.arb +++ b/lib/l10n/arb/app_tr.arb @@ -1,6 +1,7 @@ { "@@locale": "tr", "welcome": "Hoş Geldiniz", + "hello": "Selam 👋", "changeTheSettingsHere": "Buradaki ayarları değiştir", "addNewChildHere": "Buraya yeni bir çocuk ekleyin", "operationFailed": "Operation failed", diff --git a/lib/main_development.dart b/lib/main_development.dart index 6327892..516286e 100644 --- a/lib/main_development.dart +++ b/lib/main_development.dart @@ -46,7 +46,7 @@ Future main() async { ChangeNotifierProvider( create: (context) => ThemeNotifier()..initThemeMode()), ChangeNotifierProvider( - create: (context) => LanguageNotifier()), + create: (context) => LanguageNotifier()..initLocalization(),), ChangeNotifierProvider( create: (context) => AppInfoService(packageInfo)), ], diff --git a/lib/services/shared_preferences.dart b/lib/services/shared_preferences.dart index 0355921..33a5f41 100644 --- a/lib/services/shared_preferences.dart +++ b/lib/services/shared_preferences.dart @@ -1,3 +1,5 @@ +import 'dart:ui'; + import 'package:shared_preferences/shared_preferences.dart'; class CacheService { @@ -25,6 +27,12 @@ class CacheService { return darkMode; } + static Future getLocale() async { + final preferences = await SharedPreferences.getInstance(); + final status = preferences.getString('locale') ?? 'en'; + return Locale(status); + } + static Future setVisitingFlag() async { final preferences = await SharedPreferences.getInstance(); await preferences.setBool('alreadyVisited', true); @@ -51,4 +59,10 @@ class CacheService { final status = await preferences.setBool('isDarkMode', value); return status; } + + static Future setLocale({required Locale value}) async { + final preferences = await SharedPreferences.getInstance(); + final locale = await preferences.setString('locale', value.languageCode); + return locale; + } } diff --git a/lib/theme/theme.dart b/lib/theme/theme.dart index ec223c1..02e36b3 100644 --- a/lib/theme/theme.dart +++ b/lib/theme/theme.dart @@ -50,6 +50,10 @@ class AppTheme { cardTheme: CardTheme(color: CustomColors.indigoDarker), iconTheme: IconThemeData(color: CustomColors.indigoLight), dividerColor: CustomColors.indigoLight, + bottomNavigationBarTheme: BottomNavigationBarThemeData( + selectedItemColor: CustomColors.greenPrimary, + unselectedItemColor: CustomColors.indigoLight, + ), floatingActionButtonTheme: FloatingActionButtonThemeData( backgroundColor: CustomColors.indigoLight, foregroundColor: CustomColors.indigoDark, diff --git a/lib/widgets/jh_header.dart b/lib/widgets/jh_header.dart index a63672a..ba517df 100644 --- a/lib/widgets/jh_header.dart +++ b/lib/widgets/jh_header.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:times_up_flutter/l10n/l10n.dart'; import 'package:times_up_flutter/theme/theme.dart'; import 'package:times_up_flutter/widgets/jh_display_text.dart'; @@ -18,7 +19,7 @@ class JHHeader extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ JHDisplayText( - text: 'Hello 👋', + text: AppLocalizations.of(context).hello, fontSize: fontSize, maxFontSize: maxFontSize, style: TextStyle( @@ -27,7 +28,7 @@ class JHHeader extends StatelessWidget { ), ), JHDisplayText( - text: 'Welcome', + text: AppLocalizations.of(context).welcome, fontSize: fontSize, maxFontSize: maxFontSize, style: TextStyle( From 8585afea7b5e2333269655f45e35d559d0d05b8d Mon Sep 17 00:00:00 2001 From: jordyhers Date: Wed, 8 Nov 2023 16:07:06 +0100 Subject: [PATCH 23/23] chore(#43): extract method --- .../language/language_notififier.dart | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/app/features/parent_side/language/language_notififier.dart b/lib/app/features/parent_side/language/language_notififier.dart index 0405e25..b3d9af4 100644 --- a/lib/app/features/parent_side/language/language_notififier.dart +++ b/lib/app/features/parent_side/language/language_notififier.dart @@ -21,6 +21,24 @@ class LanguageNotifier extends ChangeNotifier { Future initLocalization() async { _locale = await CacheService.getLocale(); + _setLanguageString(); + languages + ..insert(languages.indexOf(_selectedLanguage), _selectedLanguage) + ..removeWhere((element) => element == _selectedLanguage); + notifyListeners(); + } + + void selectLanguage(String language) { + languages.insert(languages.indexOf(language), _selectedLanguage); + _selectedLanguage = language; + languages.removeWhere((element) => element == _selectedLanguage); + _locale = setLocale(_selectedLanguage); + CacheService.setLocale(value: _locale); + HapticFeedback.heavyImpact(); + notifyListeners(); + } + + void _setLanguageString() { switch (_locale.languageCode) { case 'en': _selectedLanguage = '🇺🇸 English󠁢'; @@ -38,21 +56,6 @@ class LanguageNotifier extends ChangeNotifier { _selectedLanguage = '🇹🇷 Turkish󠁢'; break; } - - languages - ..insert(languages.indexOf(_selectedLanguage), _selectedLanguage) - ..removeWhere((element) => element == _selectedLanguage); - notifyListeners(); - } - - void selectLanguage(String language) { - languages.insert(languages.indexOf(language), _selectedLanguage); - _selectedLanguage = language; - languages.removeWhere((element) => element == _selectedLanguage); - _locale = setLocale(_selectedLanguage); - CacheService.setLocale(value: _locale); - HapticFeedback.heavyImpact(); - notifyListeners(); } Locale setLocale(String selectedLanguage) {