├── .DS_Store
├── .github
├── dependabot.yml
├── install_secret_script.sh
└── workflows
│ ├── analyze.yml
│ ├── android_build.yml
│ └── ios_deploy.yml
├── .gitignore
├── .run
└── main.dart.run.xml
├── CONTRIBUTING.md
├── README.md
├── app
├── .firebaserc
├── .gitignore
├── .metadata
├── README.md
├── VERSION
├── analysis_options.yaml
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── ic_launcher-playstore.png
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── canopas
│ │ │ │ │ └── yourspace
│ │ │ │ │ ├── GeofenceBroadcastReceiver.kt
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ │ ├── drawable-v21
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable
│ │ │ │ ├── app_logo.png
│ │ │ │ ├── app_splash_icon.xml
│ │ │ │ ├── launch_background.xml
│ │ │ │ └── splash_inset.xml
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_foreground.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── values-night
│ │ │ │ └── styles.xml
│ │ │ │ └── values
│ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── assets
│ ├── images
│ │ ├── app_name_logo.svg
│ │ ├── connection.svg
│ │ ├── ic_30_battery_icon.svg
│ │ ├── ic_50_battery_icon.svg
│ │ ├── ic_about_us.svg
│ │ ├── ic_add_member.svg
│ │ ├── ic_add_user_icon.svg
│ │ ├── ic_calendar_icon.svg
│ │ ├── ic_close_icon.svg
│ │ ├── ic_contact_support.svg
│ │ ├── ic_distance_icon.png
│ │ ├── ic_down_arrow_icon.svg
│ │ ├── ic_edit_profile.svg
│ │ ├── ic_empty_battery_icon.svg
│ │ ├── ic_feed_location-pin.svg
│ │ ├── ic_feed_location_icon.png
│ │ ├── ic_flag_icon.svg
│ │ ├── ic_full_bettery_icon.svg
│ │ ├── ic_geofence_icon.svg
│ │ ├── ic_google_logo.svg
│ │ ├── ic_journey_empty_timeline_image.svg
│ │ ├── ic_location-feed_icon.svg
│ │ ├── ic_location.svg
│ │ ├── ic_location_off.svg
│ │ ├── ic_map_type.svg
│ │ ├── ic_message.svg
│ │ ├── ic_no_connection_icon.svg
│ │ ├── ic_normal_map.png
│ │ ├── ic_place_marker_icon.png
│ │ ├── ic_places_gym_icon.svg
│ │ ├── ic_places_home_icon.svg
│ │ ├── ic_places_library_icon.svg
│ │ ├── ic_places_park_icon.svg
│ │ ├── ic_places_school_icon.svg
│ │ ├── ic_places_work_icon.svg
│ │ ├── ic_plus_icon.svg
│ │ ├── ic_privacy_policy.svg
│ │ ├── ic_regenerate_invitation_code.svg
│ │ ├── ic_relocate_icon.svg
│ │ ├── ic_remove.svg
│ │ ├── ic_satellite_map.png
│ │ ├── ic_search_icon.svg
│ │ ├── ic_send_message.svg
│ │ ├── ic_setting.svg
│ │ ├── ic_share_two_location.svg
│ │ ├── ic_sign_out.svg
│ │ ├── ic_subscription_check_icon.svg
│ │ ├── ic_subscription_icon.svg
│ │ ├── ic_subscription_uncheck_icon.svg
│ │ ├── ic_terrain_map.png
│ │ ├── ic_time_line_history_icon.svg
│ │ ├── ic_timeline_end_location_flag_icon.png
│ │ ├── ic_timeline_journey_icon.svg
│ │ ├── ic_timeline_location_pin_icon.svg
│ │ ├── ic_timeline_start_location_icon.png
│ │ ├── ic_unknown_battery_icon.svg
│ │ ├── intro_1.svg
│ │ ├── intro_2.svg
│ │ ├── intro_3.svg
│ │ └── intro_bg.jpg
│ ├── locales
│ │ └── app_en.arb
│ └── map
│ │ └── map_theme_night.json
├── firebase.json
├── functions
│ └── node_modules
│ │ └── .package-lock.json
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── Podfile.lock
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ ├── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── 1024.png
│ │ │ │ ├── 120 1.png
│ │ │ │ ├── 120.png
│ │ │ │ ├── 152.png
│ │ │ │ ├── 167.png
│ │ │ │ ├── 180.png
│ │ │ │ ├── 20.png
│ │ │ │ ├── 29 1.png
│ │ │ │ ├── 29.png
│ │ │ │ ├── 40 1.png
│ │ │ │ ├── 40 2.png
│ │ │ │ ├── 40.png
│ │ │ │ ├── 58 1.png
│ │ │ │ ├── 58.png
│ │ │ │ ├── 60.png
│ │ │ │ ├── 76.png
│ │ │ │ ├── 80 1.png
│ │ │ │ ├── 80.png
│ │ │ │ ├── 87.png
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Grouptrack (1).png
│ │ │ │ └── README.md
│ │ ├── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── GeofencePlugin.swift
│ │ ├── LocationManager.swift
│ │ ├── Runner-Bridging-Header.h
│ │ └── Runner.entitlements
│ └── RunnerTests
│ │ └── RunnerTests.swift
├── l10n.yaml
├── lib
│ ├── domain
│ │ ├── extenstions
│ │ │ ├── api_error_extension.dart
│ │ │ ├── context_extenstions.dart
│ │ │ ├── date_formatter.dart
│ │ │ ├── lat_lng_extenstion.dart
│ │ │ ├── time_ago_extenstions.dart
│ │ │ └── widget_extensions.dart
│ │ └── fcm
│ │ │ └── notification_handler.dart
│ ├── gen
│ │ └── assets.gen.dart
│ ├── main.dart
│ └── ui
│ │ ├── app.dart
│ │ ├── components
│ │ ├── action_bottom_sheet.dart
│ │ ├── alert.dart
│ │ ├── app_logo.dart
│ │ ├── app_page.dart
│ │ ├── dashed_divider.dart
│ │ ├── error_snakebar.dart
│ │ ├── no_internet_screen.dart
│ │ ├── on_visible_callback.dart
│ │ ├── permission_dialog.dart
│ │ ├── profile_picture.dart
│ │ ├── resume_detector.dart
│ │ └── user_battery_status.dart
│ │ └── flow
│ │ ├── auth
│ │ ├── component
│ │ │ └── sign_in_method_button.dart
│ │ ├── sign_in_method_screen.dart
│ │ ├── sign_in_method_viewmodel.dart
│ │ └── sign_in_method_viewmodel.freezed.dart
│ │ ├── geofence
│ │ ├── add
│ │ │ ├── addnew
│ │ │ │ ├── add_new_place_screen.dart
│ │ │ │ ├── add_new_place_view_model.dart
│ │ │ │ └── add_new_place_view_model.freezed.dart
│ │ │ ├── components
│ │ │ │ ├── place_added_dialog.dart
│ │ │ │ └── place_marker.dart
│ │ │ ├── locate
│ │ │ │ ├── locate_on_map_screen.dart
│ │ │ │ ├── locate_on_map_view_model.dart
│ │ │ │ └── locate_on_map_view_model.freezed.dart
│ │ │ └── placename
│ │ │ │ ├── choose_place_name_screen.dart
│ │ │ │ ├── choose_place_name_view_model.dart
│ │ │ │ └── choose_place_name_view_model.freezed.dart
│ │ ├── edit
│ │ │ ├── edit_place_screen.dart
│ │ │ ├── edit_place_view_model.dart
│ │ │ └── edit_place_view_model.freezed.dart
│ │ └── places
│ │ │ ├── places_list_screen.dart
│ │ │ ├── places_list_view_model.dart
│ │ │ └── places_list_view_model.freezed.dart
│ │ ├── home
│ │ ├── components
│ │ │ └── home_top_bar.dart
│ │ ├── home_screen.dart
│ │ ├── home_screen_viewmodel.dart
│ │ ├── home_screen_viewmodel.freezed.dart
│ │ └── map
│ │ │ ├── components
│ │ │ ├── marker_generator.dart
│ │ │ ├── selected_member_detail_view.dart
│ │ │ └── space_user_footer.dart
│ │ │ ├── map_screen.dart
│ │ │ ├── map_view_model.dart
│ │ │ └── map_view_model.freezed.dart
│ │ ├── intro
│ │ ├── intro_page_item.dart
│ │ └── intro_screen.dart
│ │ ├── journey
│ │ ├── calender
│ │ │ ├── horizontal_calendar_view.dart
│ │ │ ├── horizontal_calendar_view_model.dart
│ │ │ ├── horizontal_calendar_view_model.freezed.dart
│ │ │ └── three_page_scroller.dart
│ │ ├── components
│ │ │ ├── dotted_line_view.dart
│ │ │ └── journey_map.dart
│ │ ├── detail
│ │ │ ├── user_journey_detail_screen.dart
│ │ │ ├── user_journey_detail_view_model.dart
│ │ │ └── user_journey_detail_view_model.freezed.dart
│ │ └── timeline
│ │ │ ├── journey_timeline_screen.dart
│ │ │ ├── journey_timeline_view_model.dart
│ │ │ └── journey_timeline_view_model.freezed.dart
│ │ ├── message
│ │ ├── chat
│ │ │ ├── chat_screen.dart
│ │ │ ├── chat_view_model.dart
│ │ │ └── chat_view_model.freezed.dart
│ │ ├── thread_list_screen.dart
│ │ ├── thread_list_view_model.dart
│ │ └── thread_list_view_model.freezed.dart
│ │ ├── navigation
│ │ ├── routes.dart
│ │ └── routes.g.dart
│ │ ├── onboard
│ │ ├── connection_screen.dart
│ │ ├── pick_name_screen.dart
│ │ ├── pick_name_view_model.dart
│ │ └── pick_name_view_model.freezed.dart
│ │ ├── permission
│ │ ├── enable_permission_view.dart
│ │ ├── enable_permission_view_model.dart
│ │ └── enable_permission_view_model.freezed.dart
│ │ ├── setting
│ │ ├── contact_support
│ │ │ ├── contact_support_screen.dart
│ │ │ ├── contact_support_view_model.dart
│ │ │ └── contact_support_view_model.freezed.dart
│ │ ├── profile
│ │ │ ├── profile_screen.dart
│ │ │ ├── profile_view_model.dart
│ │ │ └── profile_view_model.freezed.dart
│ │ ├── setting_screen.dart
│ │ ├── setting_view_model.dart
│ │ ├── setting_view_model.freezed.dart
│ │ ├── space
│ │ │ ├── admin
│ │ │ │ ├── change_admin_screen.dart
│ │ │ │ ├── change_admin_view_model.dart
│ │ │ │ └── change_admin_view_model.freezed.dart
│ │ │ ├── edit_space_screen.dart
│ │ │ ├── edit_space_view_model.dart
│ │ │ └── edit_space_view_model.freezed.dart
│ │ └── subscription
│ │ │ ├── subscription_screen.dart
│ │ │ ├── subscription_view_model.dart
│ │ │ └── subscription_view_model.freezed.dart
│ │ └── space
│ │ ├── create
│ │ ├── create_space_screen.dart
│ │ ├── create_space_view_model.dart
│ │ └── create_space_view_model.freezed.dart
│ │ ├── invite
│ │ └── invite_code_screen.dart
│ │ └── join
│ │ ├── join_space_screen.dart
│ │ ├── join_space_view_model.dart
│ │ └── join_space_view_model.freezed.dart
├── pubspec.lock
└── pubspec.yaml
├── build_watch
├── data
├── .gitignore
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── build.yaml
├── lib
│ ├── api
│ │ ├── auth
│ │ │ ├── api_user_service.dart
│ │ │ ├── auth_models.dart
│ │ │ ├── auth_models.freezed.dart
│ │ │ └── auth_models.g.dart
│ │ ├── location
│ │ │ ├── journey
│ │ │ │ ├── api_journey_service.dart
│ │ │ │ ├── journey.dart
│ │ │ │ ├── journey.freezed.dart
│ │ │ │ └── journey.g.dart
│ │ │ ├── location.dart
│ │ │ ├── location.freezed.dart
│ │ │ └── location.g.dart
│ │ ├── message
│ │ │ ├── api_message_service.dart
│ │ │ ├── message_models.dart
│ │ │ ├── message_models.freezed.dart
│ │ │ ├── message_models.g.dart
│ │ │ └── server_timestamp_converter.dart
│ │ ├── network
│ │ │ └── client.dart
│ │ ├── place
│ │ │ ├── api_place.dart
│ │ │ ├── api_place.freezed.dart
│ │ │ └── api_place.g.dart
│ │ ├── space
│ │ │ ├── api_space_invitation_service.dart
│ │ │ ├── api_space_service.dart
│ │ │ ├── space_models.dart
│ │ │ ├── space_models.freezed.dart
│ │ │ └── space_models.g.dart
│ │ ├── subscription
│ │ │ ├── subscription_models.dart
│ │ │ └── subscription_models.freezed.dart
│ │ └── support
│ │ │ └── api_support_service.dart
│ ├── config.dart
│ ├── converter
│ │ └── time_converter.dart
│ ├── domain
│ │ ├── journey_lat_lng_entension.dart
│ │ └── location_data_extension.dart
│ ├── feature_flags.dart
│ ├── log
│ │ ├── log_format.dart
│ │ └── logger.dart
│ ├── network
│ │ └── error.dart
│ ├── repository
│ │ ├── geofence_repository.dart
│ │ ├── journey_generator.dart
│ │ └── journey_repository.dart
│ ├── service
│ │ ├── auth_service.dart
│ │ ├── device_service.dart
│ │ ├── geofence_service.dart
│ │ ├── location_manager.dart
│ │ ├── location_service.dart
│ │ ├── message_service.dart
│ │ ├── network_service.dart
│ │ ├── permission_service.dart
│ │ ├── place_service.dart
│ │ └── space_service.dart
│ ├── storage
│ │ ├── app_preferences.dart
│ │ ├── location_caches.dart
│ │ └── preferences_provider.dart
│ └── utils
│ │ └── location_converters.dart
└── pubspec.yaml
├── docs
└── terms-of-services.md
├── screenshots
├── cover_image.png
├── create_space.gif
├── cta_banner.png
├── cta_btn.png
├── location_tracking.gif
├── message.gif
└── place.gif
└── style
├── .gitignore
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── assets
└── fonts
│ ├── inter_black_italic.ttf
│ ├── inter_bold.ttf
│ ├── inter_italic.ttf
│ ├── inter_light.ttf
│ ├── inter_medium.ttf
│ ├── inter_regular.ttf
│ ├── inter_semi_bold.ttf
│ └── kalam_bold.ttf
├── lib
├── animation
│ └── on_tap_scale.dart
├── button
│ ├── action_button.dart
│ ├── bottom_sticky_overlay.dart
│ ├── icon_primary_button.dart
│ ├── large_icon_button.dart
│ ├── primary_button.dart
│ └── secondary_button.dart
├── extenstions
│ ├── column_builder.dart
│ ├── context_extenstions.dart
│ └── date_extenstions.dart
├── indicator
│ └── progress_indicator.dart
├── style.dart
├── text
│ ├── app_text_dart.dart
│ └── app_text_field.dart
└── theme
│ ├── colors.dart
│ └── theme.dart
├── pubspec.yaml
└── test
└── style_test.dart
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/.DS_Store
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "pub"
9 | directory: "/app/"
10 | schedule:
11 | interval: "monthly"
12 | open-pull-requests-limit: 3
13 |
14 |
--------------------------------------------------------------------------------
/.github/install_secret_script.sh:
--------------------------------------------------------------------------------
1 | env:
2 | FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }}
3 | GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}
4 | GOOGLE_SERVICES_INFO_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_INFO_JSON_BASE64 }}
5 | INFO_PLIST_BASE64: ${{ secrets.INFO_PLIST_BASE64 }}
6 | CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }}
7 |
8 | echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart
9 | echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json
10 | echo $GOOGLE_SERVICES_INFO_JSON_BASE64 | base64 -di > ios/Runner/GoogleService-Info.plist
11 | echo $INFO_PLIST_BASE64 | base64 -di > ios/Runner/Info.plist
12 | cd ../data
13 | echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart
14 | cd ../app
--------------------------------------------------------------------------------
/.github/workflows/analyze.yml:
--------------------------------------------------------------------------------
1 | name: Dart Format & Analyze
2 |
3 | on: push
4 |
5 | jobs:
6 | analyze:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v3
11 | name: Checkout
12 |
13 | - uses: subosito/flutter-action@v2.12.0
14 | name: Set up Flutter SDK
15 | with:
16 | channel: 'stable'
17 | cache: true
18 |
19 | - name: Retrieve the secret and decode it to file
20 | env:
21 | MAPS_API_KEY: ${{ secrets.MAPS_API_KEY }}
22 | FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }}
23 | INFO_PLIST_BASE64: ${{ secrets.INFO_PLIST_BASE64 }}
24 | CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }}
25 |
26 | run: |
27 | cd app
28 | echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart
29 | echo $INFO_PLIST_BASE64 | base64 -di > ios/Runner/Info.plist
30 | cd ../data
31 | echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart
32 | cd ..
33 |
34 | - name: Install dependencies
35 | run: |
36 | cd data && flutter clean && flutter pub get
37 | cd ../style && flutter clean && flutter pub get
38 | cd ../app && flutter clean && flutter pub get
39 | cd ..
40 |
41 | - name: Lint test
42 | run: |
43 | cd data && flutter analyze --fatal-infos
44 | cd ../style && flutter analyze --fatal-infos
45 | cd ../app && flutter analyze --fatal-infos
46 | cd ..
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .DS_Store
3 | firebase-debug.log
--------------------------------------------------------------------------------
/.run/main.dart.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thank you so much for your interest in contributing! All types of contributions are encouraged and valued. The Project Team looks forward to your contributions.
4 |
5 | ## Filing Issues
6 |
7 | When in doubt, file an issue. We'd rather close a few duplicate issues than let a problem go unnoticed. Similarly, if you support a particular feature request, please let us know by commenting on the issue or [subscribing](https://help.github.com/articles/subscribing-to-conversations/) to the issue.
8 |
9 | If you are reporting a bug, please help speed up problem diagnosis by providing as much information as possible. Ideally, that would include a small sample project (or gist) that reproduces the problem.
10 |
11 | ## Contributing Code
12 |
13 | We actively welcome your pull requests. You can find instructions on building the project in [README.md](https://github.com/canopas/group-track-flutter).
14 |
15 | 1. Fork the repo and create your branch from `main`.
16 | 2. If you've added code that should be tested, add tests.
17 | 3. Make sure your code lints.
18 |
19 | ## Labels
20 |
21 | Labels on issues are managed by contributors; you don't have to worry about them. Here's a list of what they mean:
22 |
23 | - **bug**: Feature that should work, but doesn't.
24 | - **enhancement**: Minor tweak/addition to existing behavior.
25 | - **feature**: New behavior, bigger than enhancement.
26 | - **question**: No need for any fix, usually a usage problem.
27 | - **reproducible**: Has enough information to very easily reproduce, mostly in the form of a small project in a GitHub repo.
28 | - **repro-needed**: We need some code to be able to reproduce and debug locally; otherwise, there's not much we can do.
29 | - **duplicate**: There's another issue that already covers/tracks this.
30 | - **wontfix**: Working as intended, or won't be fixed due to compatibility or other reasons.
31 | - **invalid**: There isn't enough information to make a verdict, or unrelated.
32 | - **non-library**: Issue is not in the core library code, but rather in documentation, samples, build process, or releases.
33 |
34 | ## License
35 |
36 | By contributing to GroupTrack, you agree that your contributions will be licensed under its Apache License, Version 2.0. See the LICENSE file for details.
37 |
--------------------------------------------------------------------------------
/app/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "yourspace-regional"
4 | },
5 | "targets": {},
6 | "etags": {
7 | "yourspace-regional": {
8 | "extensionInstances": {}
9 | }
10 | },
11 | "dataconnectEmulatorConfig": {}
12 | }
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .build/
9 | .buildlog/
10 | .history
11 | .svn/
12 | .swiftpm/
13 | migrate_working_dir/
14 |
15 | # IntelliJ related
16 | *.iml
17 | *.ipr
18 | *.iws
19 | .idea/
20 |
21 | # The .vscode folder contains launch configuration and tasks you configure in
22 | # VS Code which you may wish to be included in version control, so this line
23 | # is commented out by default.
24 | #.vscode/
25 |
26 | # Flutter/Dart/Pub related
27 | **/doc/api/
28 | **/ios/Flutter/.last_build_id
29 | .dart_tool/
30 | .flutter-plugins
31 | .flutter-plugins-dependencies
32 | .pub-cache/
33 | .pub/
34 | /build/
35 | **/firebase_options.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
--------------------------------------------------------------------------------
/app/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: "41456452f29d64e8deb623a3c927524bcf9f111b"
8 | channel: "stable"
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
17 | base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
18 | - platform: android
19 | create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
20 | base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
21 | - platform: ios
22 | create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
23 | base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
24 |
25 | # User provided section
26 |
27 | # List of Local paths (relative to this file) that should be
28 | # ignored by the migrate tool.
29 | #
30 | # Files that are not part of the templates will be ignored by default.
31 | unmanaged_files:
32 | - 'lib/main.dart'
33 | - 'ios/Runner.xcodeproj/project.pbxproj'
34 |
--------------------------------------------------------------------------------
/app/README.md:
--------------------------------------------------------------------------------
1 | # App
2 |
3 | The `App` is the main module of YourSpace. It contains the core Flutter application implementation for YourSpace.
4 |
5 | ## Features
6 |
7 | - **User Interface:** Delivers the complete user interface for the YourSpace app.
8 | - **Native Integration:** Includes native code for platform-specific functionalities, such as background location tracking and geofencing.
9 | - **Components:** Contains reusable components such as buttons, views and extenstions.
--------------------------------------------------------------------------------
/app/VERSION:
--------------------------------------------------------------------------------
1 | 1.0
--------------------------------------------------------------------------------
/app/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | analyzer:
11 | errors:
12 | constant_identifier_names: ignore
13 | file_names: ignore
14 | include: package:flutter_lints/flutter.yaml
15 |
16 | linter:
17 | # The lint rules applied to this project can be customized in the
18 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
19 | # included above or to enable additional rules. A list of all available lints
20 | # and their documentation is published at https://dart.dev/lints.
21 | #
22 | # Instead of disabling a lint rule for the entire project in the
23 | # section below, it can also be suppressed for a single line of code
24 | # or a specific dart file by using the `// ignore: name_of_lint` and
25 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
26 | # producing the lint.
27 | rules:
28 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
29 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
30 |
31 | # Additional information about this file can be found at
32 | # https://dart.dev/guides/language/analysis-options
33 |
--------------------------------------------------------------------------------
/app/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 | **/google-services.json
15 |
--------------------------------------------------------------------------------
/app/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/android/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/android/app/src/main/kotlin/com/canopas/yourspace/GeofenceBroadcastReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.canopas.yourspace
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.util.Log
7 | import com.google.android.gms.location.Geofence
8 | import com.google.android.gms.location.GeofenceStatusCodes
9 | import com.google.android.gms.location.GeofencingEvent
10 | import io.flutter.embedding.engine.FlutterEngineCache
11 | import io.flutter.plugin.common.MethodChannel
12 |
13 | class GeofenceBroadcastReceiver : BroadcastReceiver() {
14 | override fun onReceive(context: Context?, intent: Intent) {
15 | val geofencingEvent = GeofencingEvent.fromIntent(intent)
16 |
17 | if (geofencingEvent == null) {
18 | Log.e("GeofenceReceiver", "Geofencing event is null")
19 | return
20 | }
21 |
22 | if (geofencingEvent.hasError()) {
23 | val errorMessage = GeofenceStatusCodes.getStatusCodeString(geofencingEvent.errorCode)
24 | Log.e("GeofenceReceiver", "Geofence error: $errorMessage")
25 | return
26 | }
27 |
28 | try {
29 | val geofenceTransition = geofencingEvent.geofenceTransition
30 |
31 | if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
32 | geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT
33 | ) {
34 | val triggeringGeofences = geofencingEvent.triggeringGeofences
35 | Log.d("GeofenceReceiver", "Geofence Alert received")
36 |
37 | triggeringGeofences?.forEach { geofence ->
38 | val placeId = geofence.requestId
39 | val method = if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER)
40 | "onEnterGeofence"
41 | else
42 | "onExitGeofence"
43 |
44 | handleGeofenceEvent(method, placeId)
45 | }
46 | } else {
47 | Log.e("GeofenceReceiver", "Geofence transition error: $geofenceTransition")
48 | }
49 | } catch (e: Exception) {
50 | Log.e("GeofenceReceiver", "Error while processing geofence alert: $e")
51 | }
52 | }
53 |
54 | private fun handleGeofenceEvent(method: String, placeId: String) {
55 | val flutterEngine = FlutterEngineCache.getInstance().get("geofence_engine")
56 | if (flutterEngine == null) {
57 | Log.d("GeofenceReceiver", "Geofence flutter engine is null")
58 | return
59 | }
60 |
61 | val methodChannel =
62 | MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "geofence_plugin")
63 | methodChannel.invokeMethod(method, mapOf("identifier" to placeId))
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/drawable/app_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/drawable/app_logo.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/drawable/app_splash_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
13 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/drawable/splash_inset.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #1679AB
4 |
--------------------------------------------------------------------------------
/app/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
17 |
20 |
21 |
--------------------------------------------------------------------------------
/app/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.9.0'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:8.2.2'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath 'com.google.gms:google-services:4.4.2'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | }
21 |
22 | rootProject.buildDir = '../build'
23 | subprojects {
24 | project.buildDir = "${rootProject.buildDir}/${project.name}"
25 | }
26 | subprojects {
27 | project.evaluationDependsOn(':app')
28 | }
29 |
30 | tasks.register("clean", Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/app/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx4G
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/app/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/app/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }
9 | settings.ext.flutterSdkPath = flutterSdkPath()
10 |
11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
12 |
13 | repositories {
14 | google()
15 | mavenCentral()
16 | gradlePluginPortal()
17 | }
18 |
19 | plugins {
20 | id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
21 | }
22 | }
23 |
24 | plugins {
25 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
26 | id "com.android.application" version '8.3.2' apply false
27 | id "com.google.gms.google-services" version "4.4.2" apply false
28 | id "com.google.firebase.crashlytics" version "3.0.2" apply false
29 | }
30 |
31 | include ":app"
32 |
--------------------------------------------------------------------------------
/app/assets/images/ic_30_battery_icon.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/assets/images/ic_50_battery_icon.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/assets/images/ic_about_us.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/images/ic_add_member.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/app/assets/images/ic_add_user_icon.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/assets/images/ic_calendar_icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/images/ic_close_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_contact_support.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/images/ic_distance_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/assets/images/ic_distance_icon.png
--------------------------------------------------------------------------------
/app/assets/images/ic_down_arrow_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_edit_profile.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/assets/images/ic_empty_battery_icon.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/assets/images/ic_feed_location-pin.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/images/ic_feed_location_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/assets/images/ic_feed_location_icon.png
--------------------------------------------------------------------------------
/app/assets/images/ic_flag_icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/images/ic_full_bettery_icon.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/assets/images/ic_geofence_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_google_logo.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/app/assets/images/ic_location-feed_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_location.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/app/assets/images/ic_location_off.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/app/assets/images/ic_map_type.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/assets/images/ic_message.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/assets/images/ic_normal_map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/assets/images/ic_normal_map.png
--------------------------------------------------------------------------------
/app/assets/images/ic_place_marker_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/assets/images/ic_place_marker_icon.png
--------------------------------------------------------------------------------
/app/assets/images/ic_places_gym_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_places_home_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_places_library_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_places_park_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_places_school_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_places_work_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_plus_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_privacy_policy.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_regenerate_invitation_code.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/images/ic_relocate_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_remove.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/app/assets/images/ic_satellite_map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/assets/images/ic_satellite_map.png
--------------------------------------------------------------------------------
/app/assets/images/ic_search_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_sign_out.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_subscription_check_icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/app/assets/images/ic_subscription_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_subscription_uncheck_icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/app/assets/images/ic_terrain_map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/assets/images/ic_terrain_map.png
--------------------------------------------------------------------------------
/app/assets/images/ic_time_line_history_icon.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/assets/images/ic_timeline_end_location_flag_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/assets/images/ic_timeline_end_location_flag_icon.png
--------------------------------------------------------------------------------
/app/assets/images/ic_timeline_journey_icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/assets/images/ic_timeline_location_pin_icon.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/assets/images/ic_timeline_start_location_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/assets/images/ic_timeline_start_location_icon.png
--------------------------------------------------------------------------------
/app/assets/images/ic_unknown_battery_icon.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/app/assets/images/intro_bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/assets/images/intro_bg.jpg
--------------------------------------------------------------------------------
/app/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "functions": [
3 | {
4 | "source": "functions",
5 | "codebase": "default",
6 | "ignore": [
7 | "node_modules",
8 | ".git",
9 | "firebase-debug.log",
10 | "firebase-debug.*.log",
11 | "*.local"
12 | ]
13 | }
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/app/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 | firebase_app_id_file.json
36 | **/GoogleService-Info.plist
37 | **/Info.plist
38 | **/ExportOptions.plist
--------------------------------------------------------------------------------
/app/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 12.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/app/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/app/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '12.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '11.4.0'
35 |
36 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
37 | target 'RunnerTests' do
38 | inherit! :search_paths
39 | end
40 | end
41 |
42 | post_install do |installer|
43 | installer.pods_project.targets.each do |target|
44 | flutter_additional_ios_build_settings(target)
45 |
46 | # Start of the permission_handler configuration
47 | target.build_configurations.each do |config|
48 |
49 | config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
50 | '$(inherited)',
51 |
52 | ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
53 | 'PERMISSION_LOCATION=1',
54 | 'PERMISSION_LOCATION_WHENINUSE=0',
55 |
56 | ## dart: PermissionGroup.notification
57 | 'PERMISSION_NOTIFICATIONS=1',
58 |
59 | ]
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/120 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/120 1.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/29 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/29 1.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/40 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/40 1.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/40 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/40 2.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/58 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/58 1.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/80 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/80 1.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Grouptrack (1).png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Grouptrack (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/group-track-flutter/a3f02d202d28f1d20051ef9857b100633c6ba996/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Grouptrack (1).png
--------------------------------------------------------------------------------
/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/app/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/ios/Runner/GeofencePlugin.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GeofencePlugin.swift
3 | // Runner
4 | //
5 | // Created by Ishita on 27/08/24.
6 | //
7 |
8 | import Foundation
9 | import CoreLocation
10 | import Flutter
11 | import UIKit
12 |
13 | class GeofenceService: NSObject, CLLocationManagerDelegate {
14 | private var locationManager: CLLocationManager!
15 | private var channel: FlutterMethodChannel?
16 |
17 | init(channel: FlutterMethodChannel? = nil) {
18 | super.init()
19 | self.locationManager = CLLocationManager()
20 | self.channel = channel
21 | self.locationManager.delegate = self
22 | }
23 |
24 | func startMonitoring(center: CLLocationCoordinate2D, radius: CLLocationDistance, identifier: String) {
25 | let region = CLCircularRegion(center: center, radius: radius, identifier: identifier)
26 | region.notifyOnEntry = true
27 | region.notifyOnExit = true
28 | self.locationManager.startMonitoring(for: region)
29 | }
30 |
31 | func stopMonitoring(identifier: String) {
32 | for region in locationManager.monitoredRegions {
33 | if let circularRegion = region as? CLCircularRegion, circularRegion.identifier == identifier {
34 | self.locationManager.stopMonitoring(for: region)
35 | }
36 | }
37 | }
38 |
39 | func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
40 | if let circularRegion = region as? CLCircularRegion {
41 | channel?.invokeMethod("onEnterGeofence", arguments: ["identifier": circularRegion.identifier])
42 | }
43 | }
44 |
45 | func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
46 | if let circularRegion = region as? CLCircularRegion {
47 | channel?.invokeMethod("onExitGeofence", arguments: ["identifier": circularRegion.identifier])
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/app/ios/Runner/Runner.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 | com.apple.developer.applesignin
8 |
9 | Default
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/ios/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/app/l10n.yaml:
--------------------------------------------------------------------------------
1 | arb-dir: assets/locales
2 | template-arb-file: app_en.arb
3 | output-localization-file: app_localizations.dart
--------------------------------------------------------------------------------
/app/lib/domain/extenstions/api_error_extension.dart:
--------------------------------------------------------------------------------
1 | import 'package:data/network/error.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart';
4 |
5 |
6 | extension AppErrorExtensions on Object {
7 | String l10nMessage(BuildContext context) {
8 | switch (runtimeType) {
9 | case const (NoInternetConnectionError):
10 | return context.l10n.errorNoConnection;
11 | case const (GenericError):
12 | return context.l10n.errorGeneric;
13 | case const (String):
14 | return this as String;
15 | case const (StringError):
16 | return (this as StringError).error;
17 | case const (ApiError):
18 | return (this as ApiError).message ?? context.l10n.errorGeneric;
19 | default:
20 | return context.l10n.errorGeneric;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/lib/domain/extenstions/context_extenstions.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
3 |
4 | extension BuildContextExtensions on BuildContext {
5 | AppLocalizations get l10n => AppLocalizations.of(this)!;
6 | }
7 |
--------------------------------------------------------------------------------
/app/lib/domain/extenstions/time_ago_extenstions.dart:
--------------------------------------------------------------------------------
1 | extension TimeAgoExtension on int? {
2 | String timeAgo() {
3 | if (this == null) return "";
4 |
5 | final DateTime now = DateTime.now();
6 | final DateTime date = DateTime.fromMillisecondsSinceEpoch(this!);
7 |
8 | final Duration diff = now.difference(date);
9 |
10 | if (diff.inSeconds < 60) {
11 | return "just now";
12 | } else if (diff.inMinutes < 60) {
13 | return "${diff.inMinutes} minutes ago";
14 | } else if (diff.inHours < 24) {
15 | return "${diff.inHours} hours ago";
16 | } else if (diff.inDays < 7) {
17 | return "${diff.inDays} days ago";
18 | } else if (diff.inDays < 30) {
19 | return "${diff.inDays ~/ 7} weeks ago";
20 | } else if (diff.inDays < 365) {
21 | return "${diff.inDays ~/ 30} months ago";
22 | } else {
23 | return "${diff.inDays ~/ 365} years ago";
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/lib/domain/extenstions/widget_extensions.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | void runPostFrame(Function() block) {
4 | WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
5 | block();
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/app/lib/ui/components/app_logo.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_svg/svg.dart';
3 |
4 | import '../../gen/assets.gen.dart';
5 |
6 | class AppLogo extends StatelessWidget {
7 | final Color? contentColor;
8 |
9 | const AppLogo({super.key, this.contentColor});
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Column(
14 | crossAxisAlignment: CrossAxisAlignment.center,
15 | mainAxisAlignment: MainAxisAlignment.center,
16 | children: [
17 | SvgPicture.asset(Assets.images.appNameLogo),
18 | ],
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/lib/ui/components/dashed_divider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class DashedLineVerticalPainter extends CustomPainter {
5 | final Color color;
6 | DashedLineVerticalPainter({required this.color});
7 |
8 | @override
9 | void paint(Canvas canvas, Size size) {
10 | double dashHeight = 5, dashSpace = 3, startY = 0;
11 | final paint = Paint()
12 | ..color = color
13 | ..strokeWidth = size.width;
14 | while (startY < size.height) {
15 | canvas.drawLine(Offset(0, startY), Offset(0, startY + dashHeight), paint);
16 | startY += dashHeight + dashSpace;
17 | }
18 | }
19 |
20 | @override
21 | bool shouldRepaint(CustomPainter oldDelegate) => false;
22 | }
--------------------------------------------------------------------------------
/app/lib/ui/components/error_snakebar.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:data/network/error.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter/services.dart';
6 | import 'package:fluttertoast/fluttertoast.dart';
7 | import 'package:yourspace_flutter/domain/extenstions/api_error_extension.dart';
8 |
9 | void showErrorSnackBar(BuildContext context, Object error) {
10 | HapticFeedback.mediumImpact();
11 | final message = ApiError.fromError(error).l10nMessage(context);
12 | showSnackBar(context, message, length: SnackBarLength.long);
13 | }
14 |
15 | void showSnackBar(
16 | BuildContext context,
17 | String text, {
18 | SnackBarLength length = SnackBarLength.short,
19 | }) {
20 | if (Platform.isIOS) {
21 | Fluttertoast.showToast(
22 | msg: text,
23 | timeInSecForIosWeb: length.seconds,
24 | gravity: ToastGravity.BOTTOM,
25 | );
26 | } else {
27 | final snackBar = SnackBar(
28 | content: Text(text),
29 | behavior: SnackBarBehavior.floating,
30 | duration: Duration(seconds: length.seconds),
31 | );
32 | ScaffoldMessenger.of(context).removeCurrentSnackBar();
33 | ScaffoldMessenger.of(context).showSnackBar(snackBar);
34 | }
35 | }
36 |
37 | enum SnackBarLength {
38 | short(1),
39 | long(2);
40 |
41 | final int seconds;
42 |
43 | const SnackBarLength(this.seconds);
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/app/lib/ui/components/no_internet_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:connectivity_plus/connectivity_plus.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter_svg/svg.dart';
4 | import 'package:style/button/primary_button.dart';
5 | import 'package:style/extenstions/context_extenstions.dart';
6 | import 'package:style/text/app_text_dart.dart';
7 | import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart';
8 |
9 | import '../../gen/assets.gen.dart';
10 |
11 | class NoInternetScreen extends StatefulWidget {
12 | final Function() onPressed;
13 |
14 | const NoInternetScreen({super.key, required this.onPressed});
15 |
16 | @override
17 | State createState() => _NoInternetScreenState();
18 | }
19 |
20 | class _NoInternetScreenState extends State {
21 | @override
22 | Widget build(BuildContext context) {
23 | return Center(
24 | child: Padding(
25 | padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 40),
26 | child: SingleChildScrollView(
27 | child: Column(
28 | mainAxisAlignment: MainAxisAlignment.center,
29 | children: [
30 | SvgPicture.asset(Assets.images.icNoConnectionIcon),
31 | const SizedBox(height: 40),
32 | Text(
33 | context.l10n.on_internet_error_title,
34 | style: AppTextStyle.header1
35 | .copyWith(color: context.colorScheme.textPrimary),
36 | ),
37 | const SizedBox(height: 16),
38 | Text(
39 | context.l10n.on_internet_error_sub_title,
40 | style: AppTextStyle.subtitle2
41 | .copyWith(color: context.colorScheme.textSecondary),
42 | textAlign: TextAlign.center,
43 | ),
44 | const SizedBox(height: 40),
45 | PrimaryButton(
46 | context.l10n.common_retry,
47 | edgeInsets: const EdgeInsets.symmetric(
48 | vertical: 14.0, horizontal: 42.0),
49 | expanded: false,
50 | onPressed: () {
51 | widget.onPressed();
52 | },
53 | ),
54 | ],
55 | ),
56 | ),
57 | ),
58 | );
59 | }
60 | }
61 |
62 | Future checkInternetConnectivity() async {
63 | final result = await Connectivity().checkConnectivity();
64 | return result.first == ConnectivityResult.none;
65 | }
66 |
--------------------------------------------------------------------------------
/app/lib/ui/components/on_visible_callback.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | class OnVisibleCallback extends StatefulWidget {
4 | final void Function() onVisible;
5 | final Widget child;
6 |
7 | const OnVisibleCallback({
8 | super.key,
9 | required this.onVisible,
10 | required this.child,
11 | });
12 |
13 | @override
14 | State createState() => _OnCreateState();
15 | }
16 |
17 | class _OnCreateState extends State {
18 | @override
19 | void initState() {
20 | widget.onVisible();
21 | super.initState();
22 | }
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return widget.child;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/lib/ui/components/permission_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:style/button/primary_button.dart';
3 | import 'package:style/extenstions/context_extenstions.dart';
4 | import 'package:style/text/app_text_dart.dart';
5 | import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart';
6 |
7 | class PermissionDialog extends StatelessWidget {
8 | final String title;
9 | final String subTitle1;
10 | final String? subTitle2;
11 | final String? dismissBtn;
12 | final String? confirmBtn;
13 | final VoidCallback onDismiss;
14 | final VoidCallback goToSettings;
15 |
16 | const PermissionDialog({
17 | super.key,
18 | required this.title,
19 | required this.subTitle1,
20 | this.subTitle2,
21 | this.dismissBtn,
22 | this.confirmBtn,
23 | required this.onDismiss,
24 | required this.goToSettings,
25 | });
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return AlertDialog(
30 | shape: RoundedRectangleBorder(
31 | borderRadius: BorderRadius.circular(16),
32 | ),
33 | title: Text(
34 | title,
35 | textAlign: TextAlign.center,
36 | style: AppTextStyle.header3,
37 | ),
38 | content: Column(
39 | mainAxisSize: MainAxisSize.min,
40 | children: [
41 | Text(
42 | subTitle1,
43 | textAlign: TextAlign.center,
44 | style: AppTextStyle.body1
45 | .copyWith(color: context.colorScheme.textDisabled),
46 | ),
47 | if (subTitle2 != null) ...[
48 | const SizedBox(height: 24),
49 | Text(
50 | subTitle2!,
51 | textAlign: TextAlign.center,
52 | style: AppTextStyle.body2
53 | .copyWith(color: context.colorScheme.textDisabled),
54 | ),
55 | ],
56 | ],
57 | ),
58 | actions: [
59 | PrimaryButton(confirmBtn ?? context.l10n.common_go_to_setting,
60 | onPressed: goToSettings),
61 | if (dismissBtn != null) ...[
62 | const SizedBox(height: 16),
63 | OutlinedPrimaryButton(
64 | dismissBtn!,
65 | onPressed: onDismiss,
66 | foreground: context.colorScheme.primary,
67 | ),
68 | ],
69 | ],
70 | );
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/lib/ui/components/profile_picture.dart:
--------------------------------------------------------------------------------
1 | import 'package:cached_network_image/cached_network_image.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:style/extenstions/context_extenstions.dart';
4 | import 'package:style/indicator/progress_indicator.dart';
5 | import 'package:style/text/app_text_dart.dart';
6 |
7 | class ProfileImage extends StatefulWidget {
8 | final double size;
9 | final String profileImageUrl;
10 | final String firstLetter;
11 | final TextStyle? style;
12 | final Color? backgroundColor;
13 | final Color? borderColor;
14 |
15 | const ProfileImage({
16 | super.key,
17 | this.size = 64,
18 | required this.profileImageUrl,
19 | required this.firstLetter,
20 | this.style,
21 | this.backgroundColor,
22 | this.borderColor,
23 | });
24 |
25 | @override
26 | State createState() => _ProfileImageState();
27 | }
28 |
29 | class _ProfileImageState extends State {
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return SizedBox(
34 | width: widget.size,
35 | height: widget.size,
36 | child: ClipRRect(
37 | borderRadius: BorderRadius.circular(widget.size / 2),
38 | child: widget.profileImageUrl.isNotEmpty
39 | ? CachedNetworkImage(
40 | imageUrl: widget.profileImageUrl,
41 | placeholder: (context, url) => const AppProgressIndicator(
42 | size: AppProgressIndicatorSize.small),
43 | errorWidget: (context, url, error) => const Icon(Icons.error),
44 | fit: BoxFit.cover,
45 | )
46 | : Container(
47 | decoration: BoxDecoration(
48 | color: widget.backgroundColor ??
49 | context.colorScheme.containerInverseHigh,
50 | border: Border.all(width: 0.5, color: widget.borderColor ?? Colors.transparent),
51 | borderRadius: BorderRadius.circular(widget.size / 2),
52 | ),
53 | child: Center(
54 | child: Text(
55 | widget.firstLetter,
56 | style: widget.style ?? AppTextStyle.subtitle2
57 | .copyWith(color: context.colorScheme.textInversePrimary)),
58 | ),
59 | ),
60 | ),
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/lib/ui/components/resume_detector.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:uuid/uuid.dart';
3 | import 'package:visibility_detector/visibility_detector.dart';
4 |
5 | class ResumeDetector extends StatefulWidget {
6 | final Function() onResume;
7 | final Widget child;
8 |
9 | const ResumeDetector({
10 | super.key,
11 | required this.onResume,
12 | required this.child,
13 | });
14 |
15 | @override
16 | State createState() => _ResumeDetectorState();
17 | }
18 |
19 | class _ResumeDetectorState extends State {
20 | final String _key = const Uuid().v4();
21 |
22 | var _lastNotifiedTime = DateTime.now();
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return VisibilityDetector(
27 | key: Key(_key),
28 | child: widget.child,
29 | onVisibilityChanged: (info) {
30 | if (info.visibleFraction == 1) {
31 | if (DateTime.now().difference(_lastNotifiedTime).inMilliseconds >
32 | 1000) {
33 | widget.onResume();
34 | _lastNotifiedTime = DateTime.now();
35 | }
36 | }
37 | },
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/lib/ui/components/user_battery_status.dart:
--------------------------------------------------------------------------------
1 | import 'package:data/api/auth/auth_models.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_svg/svg.dart';
5 | import 'package:style/extenstions/context_extenstions.dart';
6 | import 'package:style/text/app_text_dart.dart';
7 |
8 | import '../../gen/assets.gen.dart';
9 |
10 | class UserBatteryStatus extends StatelessWidget {
11 | final ApiUser user;
12 |
13 | const UserBatteryStatus({super.key, required this.user});
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | final batteryPct = user.battery_pct ?? 0;
18 | String icon;
19 | Color color;
20 |
21 | if (batteryPct > 70) {
22 | icon = Assets.images.icFullBetteryIcon;
23 | color = context.colorScheme.positive;
24 | } else if (batteryPct > 50) {
25 | icon = Assets.images.ic50BatteryIcon;
26 | color = context.colorScheme.positive;
27 | } else if (batteryPct > 30) {
28 | icon = Assets.images.ic30BatteryIcon;
29 | color = context.colorScheme.positive;
30 | } else if (batteryPct >= 1) {
31 | icon = Assets.images.icEmptyBatteryIcon;
32 | color = context.colorScheme.alert;
33 | } else {
34 | icon = Assets.images.icUnknownBatteryIcon;
35 | color = context.colorScheme.textDisabled;
36 | }
37 |
38 | return Row(
39 | children: [
40 | SvgPicture.asset(
41 | icon,
42 | colorFilter: ColorFilter.mode(color, BlendMode.srcATop),
43 | ),
44 | Visibility(
45 | visible: batteryPct >= 1,
46 | child: Text(
47 | '${batteryPct.toInt()}%',
48 | style: AppTextStyle.caption
49 | .copyWith(color: context.colorScheme.textPrimary),
50 | ),
51 | )
52 | ],
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/lib/ui/flow/auth/component/sign_in_method_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:style/animation/on_tap_scale.dart';
3 | import 'package:style/extenstions/context_extenstions.dart';
4 | import 'package:style/indicator/progress_indicator.dart';
5 | import 'package:style/text/app_text_dart.dart';
6 |
7 | class SignInMethodButton extends StatelessWidget {
8 | final Function()? onTap;
9 | final String title;
10 | final bool isLoading;
11 | final Widget? icon;
12 | final Color? backgroundColor;
13 | final Color? foregroundColor;
14 |
15 | const SignInMethodButton({
16 | super.key,
17 | this.onTap,
18 | this.backgroundColor,
19 | this.foregroundColor,
20 | required this.title,
21 | this.icon,
22 | this.isLoading = false,
23 | });
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | return OnTapScale(
28 | onTap: onTap,
29 | enabled: onTap != null && !isLoading,
30 | child: Container(
31 | alignment: Alignment.center,
32 | width: double.infinity,
33 | constraints: const BoxConstraints(minHeight: 48),
34 | padding: const EdgeInsets.symmetric(horizontal: 12),
35 | decoration: BoxDecoration(
36 | color: backgroundColor ?? context.colorScheme.primary,
37 | borderRadius: BorderRadius.circular(24),
38 | ),
39 | child: Visibility(
40 | visible: isLoading,
41 | replacement: Row(
42 | mainAxisAlignment: MainAxisAlignment.center,
43 | children: [
44 | icon ?? const SizedBox(),
45 | Visibility(
46 | visible: icon != null,
47 | child: const SizedBox(width: 8),
48 | ),
49 | Text(
50 | title,
51 | style: AppTextStyle.button.copyWith(
52 | color: foregroundColor ?? context.colorScheme.onPrimary,
53 | ),
54 | ),
55 | ],
56 | ),
57 | child: AppProgressIndicator(
58 | color: foregroundColor,
59 | size: AppProgressIndicatorSize.small,
60 | ),
61 | ),
62 | ),
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:data/api/place/api_place.dart';
4 | import 'package:data/log/logger.dart';
5 | import 'package:data/service/location_manager.dart';
6 | import 'package:data/service/place_service.dart';
7 | import 'package:flutter_riverpod/flutter_riverpod.dart';
8 | import 'package:freezed_annotation/freezed_annotation.dart';
9 | import 'package:geolocator/geolocator.dart';
10 |
11 | import '../../../../components/no_internet_screen.dart';
12 |
13 | part 'add_new_place_view_model.freezed.dart';
14 |
15 | final addNewPlaceStateProvider = StateNotifierProvider.autoDispose<
16 | AddNewPlaceViewNotifier, AddNewPlaceState>((ref) {
17 | return AddNewPlaceViewNotifier(
18 | ref.read(placeServiceProvider),
19 | ref.read(locationManagerProvider),
20 | );
21 | });
22 |
23 | class AddNewPlaceViewNotifier extends StateNotifier {
24 | final PlaceService placeService;
25 | final LocationManager locationManager;
26 |
27 | AddNewPlaceViewNotifier(
28 | this.placeService,
29 | this.locationManager,
30 | ) : super(const AddNewPlaceState());
31 |
32 | Timer? _debounce;
33 | Position? _position;
34 |
35 | void onPlaceNameChanged(String value) {
36 | if (_debounce?.isActive ?? false) _debounce!.cancel();
37 |
38 | _debounce = Timer(const Duration(milliseconds: 500), () async {
39 | final isNetworkOff = await checkInternetConnectivity();
40 | state = state.copyWith(isNetworkOff: isNetworkOff);
41 | if (isNetworkOff) return;
42 |
43 | fidePlace(value);
44 | });
45 | }
46 |
47 | void fidePlace(String value) async {
48 | if (value.isEmpty) {
49 | state = state.copyWith(places: []);
50 | return;
51 | }
52 | try {
53 | state = state.copyWith(loading: true);
54 | final position = await locationManager.getLastLocation();
55 |
56 | if (position != null &&
57 | position.latitude != _position?.latitude &&
58 | position.longitude != _position?.longitude) {
59 | _position = position;
60 | }
61 | final places = await placeService.searchNearbyPlaces(
62 | value,
63 | _position?.latitude,
64 | _position?.longitude,
65 | );
66 | state = state.copyWith(places: places, loading: false, error: null);
67 | } catch (error, stack) {
68 | state = state.copyWith(error: error, loading: false);
69 | logger.e(
70 | 'AddNewPlaceViewNotifier: Error while finding place',
71 | error: error,
72 | stackTrace: stack,
73 | );
74 | }
75 | }
76 | }
77 |
78 | @freezed
79 | class AddNewPlaceState with _$AddNewPlaceState {
80 | const factory AddNewPlaceState({
81 | @Default(false) loading,
82 | @Default(false) isNetworkOff,
83 | @Default([]) List places,
84 | Object? error,
85 | }) = _AddNewPlaceState;
86 | }
87 |
--------------------------------------------------------------------------------
/app/lib/ui/flow/geofence/add/components/place_marker.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_svg/svg.dart';
4 | import 'package:style/extenstions/context_extenstions.dart';
5 |
6 | import '../../../../../gen/assets.gen.dart';
7 |
8 | class PlaceMarker extends StatelessWidget {
9 | final double radius;
10 |
11 | const PlaceMarker({super.key, required this.radius});
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Stack(
16 | alignment: Alignment.center,
17 | children: [
18 | ClipRect(
19 | child: OverflowBox(
20 | maxHeight: radius,
21 | maxWidth: radius,
22 | child: AnimatedContainer(
23 | duration: const Duration(milliseconds: 300),
24 | width: radius,
25 | height: radius,
26 | decoration: BoxDecoration(
27 | borderRadius: BorderRadius.circular(radius),
28 | color: context.colorScheme.primary.withAlpha((0.5 * 255).toInt()),
29 | ),
30 | ),
31 | ),
32 | ),
33 | Container(
34 | width: 40,
35 | height: 40,
36 | decoration: BoxDecoration(
37 | borderRadius: BorderRadius.circular(30),
38 | color: context.colorScheme.onPrimary,
39 | ),
40 | child: Padding(
41 | padding: const EdgeInsets.all(4),
42 | child: SvgPicture.asset(
43 | Assets.images.icLocationFeedIcon,
44 | colorFilter: ColorFilter.mode(
45 | context.colorScheme.primary,
46 | BlendMode.srcATop,
47 | ),
48 | ),
49 | ),
50 | ),
51 | ],
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/lib/ui/flow/intro/intro_page_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter_svg/svg.dart';
3 | import 'package:style/extenstions/context_extenstions.dart';
4 | import 'package:style/text/app_text_dart.dart';
5 | import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart';
6 |
7 | import '../../../gen/assets.gen.dart';
8 |
9 | const maxImageSize = 400.0;
10 |
11 | class IntroPageItem {
12 | final String title;
13 | final String subtitle;
14 | final String image;
15 |
16 | IntroPageItem({
17 | required this.title,
18 | required this.subtitle,
19 | required this.image,
20 | });
21 |
22 | static List generate(BuildContext context) {
23 | return [
24 | IntroPageItem(
25 | title: context.l10n.intro_1_title,
26 | subtitle: context.l10n.intro_1_subTitle,
27 | image: Assets.images.intro1),
28 | IntroPageItem(
29 | title: context.l10n.intro_2_title,
30 | subtitle: context.l10n.intro_2_subTitle,
31 | image: Assets.images.intro2),
32 | IntroPageItem(
33 | title: context.l10n.intro_3_title,
34 | subtitle: context.l10n.intro_3_subTitle,
35 | image: Assets.images.intro3),
36 | ];
37 | }
38 | }
39 |
40 | class IntroPageWidget extends StatelessWidget {
41 | final IntroPageItem item;
42 |
43 | const IntroPageWidget({super.key, required this.item});
44 |
45 | @override
46 | Widget build(BuildContext context) {
47 | final screenSize = MediaQuery.of(context).size.width;
48 | final size = screenSize > maxImageSize ? maxImageSize : screenSize - 32;
49 |
50 | return Padding(
51 | padding: const EdgeInsets.symmetric(horizontal: 16),
52 | child: Center(
53 | child: SingleChildScrollView(
54 | child: Column(
55 | crossAxisAlignment: CrossAxisAlignment.center,
56 | mainAxisAlignment: MainAxisAlignment.center,
57 | children: [
58 | const SizedBox(height: 24),
59 | Text(
60 | item.title,
61 | style: AppTextStyle.header1
62 | .copyWith(color: context.colorScheme.textPrimary),
63 | ),
64 | const SizedBox(height: 24),
65 | SvgPicture.asset(item.image, width: size, height: size),
66 | const SizedBox(height: 16),
67 | Text(
68 | item.subtitle,
69 | textAlign: TextAlign.center,
70 | style: AppTextStyle.subtitle1
71 | .copyWith(color: context.colorScheme.textSecondary),
72 | ),
73 | const SizedBox(height: 24),
74 | ],
75 | ),
76 | ),
77 | ),
78 | );
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/lib/ui/flow/journey/calender/horizontal_calendar_view_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:style/extenstions/date_extenstions.dart';
4 |
5 | part 'horizontal_calendar_view_model.freezed.dart';
6 |
7 | final horizontalCalendarViewStateProvider = StateNotifierProvider.autoDispose<
8 | HorizontalCalendarViewModel, CalendarViewState>((ref) {
9 | return HorizontalCalendarViewModel();
10 | });
11 |
12 | class HorizontalCalendarViewModel extends StateNotifier {
13 | HorizontalCalendarViewModel()
14 | : super(
15 | CalendarViewState(
16 | weekStartDate: DateTime.now().startOfDay,
17 | selectedDate: DateTime.now().startOfDay,
18 | ),
19 | ) {
20 | setCurrentWeekStartDate();
21 | }
22 |
23 | void setCurrentWeekStartDate() {
24 | final currentDate = state.selectedDate;
25 | // Monday
26 | final dayOfWeek = currentDate.weekday;
27 | final daysToSubtract = dayOfWeek == 1 ? 0 : dayOfWeek - 1;
28 | final currentWeekStartDate =
29 | currentDate.subtract(Duration(days: daysToSubtract));
30 | state = state.copyWith(weekStartDate: currentWeekStartDate);
31 | }
32 |
33 | void onSwipeWeek(int direction) {
34 | final currentWeekStartDate = state.weekStartDate;
35 | final newWeekStartDate =
36 | currentWeekStartDate.add(Duration(days: direction * 7));
37 | if (newWeekStartDate.isAfter(DateTime.now().startOfDay)) {
38 | return;
39 | }
40 | state = state.copyWith(weekStartDate: newWeekStartDate);
41 | setContainsToday();
42 | }
43 |
44 | void setSelectedDate(DateTime? date, {bool isPickerDate = false}) {
45 | state = state.copyWith(
46 | selectedDate: date?.startOfDay ?? DateTime.now().startOfDay);
47 | if (isPickerDate && date != null) {
48 | onSelectDateFromDatePicker(date);
49 | }
50 | }
51 |
52 | void onSelectDateFromDatePicker(DateTime date) {
53 | state = state.copyWith(weekStartDate: date.startOfWeek);
54 | setContainsToday();
55 | }
56 |
57 | void setContainsToday() {
58 | final DateTime today = DateTime.now();
59 | final DateTime endOfWeek = state.weekStartDate.add(const Duration(days: 6));
60 |
61 | final containsToday =
62 | today.isAfter(state.weekStartDate) && today.isBefore(endOfWeek);
63 | state = state.copyWith(containsToday: containsToday);
64 | }
65 |
66 | void goToToday() {
67 | setSelectedDate(DateTime.now());
68 | setCurrentWeekStartDate();
69 | setContainsToday();
70 | }
71 | }
72 |
73 | @freezed
74 | class CalendarViewState with _$CalendarViewState {
75 | const factory CalendarViewState({
76 | required DateTime selectedDate,
77 | required DateTime weekStartDate,
78 | @Default(true) bool containsToday,
79 | }) = _CalendarViewState;
80 | }
81 |
--------------------------------------------------------------------------------
/app/lib/ui/flow/onboard/connection_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_svg/svg.dart';
3 | import 'package:style/button/bottom_sticky_overlay.dart';
4 | import 'package:style/button/primary_button.dart';
5 | import 'package:style/button/secondary_button.dart';
6 | import 'package:style/extenstions/context_extenstions.dart';
7 | import 'package:style/text/app_text_dart.dart';
8 | import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart';
9 | import 'package:yourspace_flutter/ui/components/app_page.dart';
10 | import 'package:yourspace_flutter/ui/flow/navigation/routes.dart';
11 |
12 | import '../../../gen/assets.gen.dart';
13 |
14 | class ConnectionScreen extends StatefulWidget {
15 | const ConnectionScreen({super.key});
16 |
17 | @override
18 | State createState() => _ConnectionScreenState();
19 | }
20 |
21 | class _ConnectionScreenState extends State {
22 | @override
23 | Widget build(BuildContext context) {
24 | return AppPage(
25 | body: _body(context),
26 | );
27 | }
28 |
29 | Widget _body(BuildContext context) {
30 | return Center(
31 | child: Stack(children: [
32 | ListView(
33 | children: [
34 | const SizedBox(height: 40),
35 | Padding(
36 | padding: const EdgeInsets.symmetric(horizontal: 16),
37 | child: Text(
38 | context.l10n.connection_share_title,
39 | style: AppTextStyle.header3.copyWith(
40 | color: context.colorScheme.textPrimary,
41 | ),
42 | textAlign: TextAlign.center,
43 | ),
44 | ),
45 | const SizedBox(height: 40),
46 | SvgPicture.asset(Assets.images.connection),
47 | const SizedBox(height: 40),
48 | Padding(
49 | padding: const EdgeInsets.symmetric(horizontal: 16),
50 | child: Text(
51 | context.l10n.connection_share_subtitle,
52 | style: AppTextStyle.subtitle1.copyWith(
53 | color: context.colorScheme.textSecondary,
54 | ),
55 | textAlign: TextAlign.center,
56 | ),
57 | )
58 | ]),
59 | _continueAndSkipButton(context),
60 | ]),
61 | );
62 | }
63 |
64 | Widget _continueAndSkipButton(BuildContext context) {
65 | return BottomStickyOverlay(
66 | child: Column(children: [
67 | PrimaryButton(
68 | context.l10n.connection_continue_title,
69 | onPressed: () {
70 | const JoinSpaceRoute(fromOnboard: true).go(context);
71 | },
72 | ),
73 | const SizedBox(height: 16),
74 | SecondaryButton(
75 | context.l10n.common_skip,
76 | onPressed: () {
77 | HomeRoute().go(context);
78 | },
79 | )
80 | ]),
81 | );
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/lib/ui/flow/onboard/pick_name_view_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:data/api/auth/auth_models.dart';
2 | import 'package:data/log/logger.dart';
3 | import 'package:data/service/auth_service.dart';
4 | import 'package:data/storage/app_preferences.dart';
5 | import 'package:flutter/cupertino.dart';
6 | import 'package:flutter_riverpod/flutter_riverpod.dart';
7 | import 'package:freezed_annotation/freezed_annotation.dart';
8 |
9 | part 'pick_name_view_model.freezed.dart';
10 |
11 | final pickNameStateNotifierProvider = StateNotifierProvider.autoDispose<
12 | PickNameStateNotifier, PickNameState>((ref) {
13 | return PickNameStateNotifier(
14 | ref.watch(authServiceProvider),
15 | ref.watch(currentUserPod),
16 | );
17 | });
18 |
19 | class PickNameStateNotifier extends StateNotifier {
20 | final AuthService _authService;
21 | final ApiUser? user;
22 |
23 | PickNameStateNotifier(this._authService, this.user)
24 | : super(PickNameState(firstName: TextEditingController(), lastName: TextEditingController(), user: user!));
25 |
26 | void enableNextButton() {
27 | state = state.copyWith(enableBtn: state.firstName.text.isNotEmpty && state.firstName.text.length >= 3);
28 | }
29 |
30 | Future saveUser(ApiUser user) async {
31 | try {
32 | state = state.copyWith(savingUser: true, error: null);
33 | final newUser = user.copyWith(first_name: state.firstName.text, last_name: state.lastName.text);
34 | _authService.updateCurrentUser(newUser);
35 | state = state.copyWith(savingUser: false, saved: true, error: null);
36 | } catch (error, stack) {
37 | state = state.copyWith(savingUser: false, error: error);
38 | logger.e(
39 | 'PickNameStateNotifier: error while save user',
40 | error: error,
41 | stackTrace: stack,
42 | );
43 | }
44 | }
45 | }
46 |
47 | @freezed
48 | class PickNameState with _$PickNameState {
49 | const factory PickNameState({
50 | @Default(false) bool enableBtn,
51 | @Default(false) bool savingUser,
52 | @Default(false) bool saved,
53 | Object? error,
54 | required TextEditingController firstName,
55 | required TextEditingController lastName,
56 | required ApiUser user,
57 | }) = _PickNameState;
58 | }
59 |
--------------------------------------------------------------------------------
/app/lib/ui/flow/setting/space/admin/change_admin_view_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:data/api/auth/auth_models.dart';
2 | import 'package:data/api/space/space_models.dart';
3 | import 'package:data/log/logger.dart';
4 | import 'package:data/service/space_service.dart';
5 | import 'package:data/storage/app_preferences.dart';
6 | import 'package:flutter_riverpod/flutter_riverpod.dart';
7 | import 'package:freezed_annotation/freezed_annotation.dart';
8 |
9 | part 'change_admin_view_model.freezed.dart';
10 |
11 | final changeAdminViewStateProvider = StateNotifierProvider.autoDispose<
12 | ChangAdminViewNotifier, ChangeAdminViewState>(
13 | (ref) => ChangAdminViewNotifier(
14 | ref.read(spaceServiceProvider),
15 | ref.read(currentUserPod),
16 | ),
17 | );
18 |
19 | class ChangAdminViewNotifier extends StateNotifier {
20 | final SpaceService spaceService;
21 | final ApiUser? user;
22 |
23 | ChangAdminViewNotifier(this.spaceService, this.user)
24 | : super(const ChangeAdminViewState()) {
25 | state = state.copyWith(currentUserId: user?.id ?? '');
26 | }
27 |
28 | void updateSpaceAdmin(ApiSpace space) async {
29 | try {
30 | state = state.copyWith(adminIdChanged: false, saving: true);
31 | await spaceService.updateSpace(space.copyWith(admin_id: state.newAdminId));
32 | state = state.copyWith(adminIdChanged: true, error: null, saving: false);
33 | } catch (error, stack) {
34 | state = state.copyWith(error: error);
35 | logger.e('ChangeAdminViewNotifier: error while update space admin id',
36 | error: error, stackTrace: stack);
37 | }
38 | }
39 |
40 | void updateNewAdminId(String id) {
41 | state = state.copyWith(newAdminId: id, allowSave: true);
42 | }
43 | }
44 |
45 | @freezed
46 | class ChangeAdminViewState with _$ChangeAdminViewState {
47 | const factory ChangeAdminViewState({
48 | @Default(false) bool allowSave,
49 | @Default(false) bool saving,
50 | @Default(false) bool adminIdChanged,
51 | @Default('') String newAdminId,
52 | @Default('') String currentUserId,
53 | Object? error,
54 | }) = _ChangeAdminViewState;
55 | }
56 |
--------------------------------------------------------------------------------
/app/lib/ui/flow/setting/subscription/subscription_view_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:data/api/subscription/subscription_models.dart';
4 |
5 | part 'subscription_view_model.freezed.dart';
6 |
7 | const freePlan = "free_plan";
8 | const proPlan = "pro_plan";
9 |
10 | final subscriptionViewProvider = StateNotifierProvider.autoDispose<
11 | SubscriptionViewNotifier, SubscriptionState>(
12 | (ref) => SubscriptionViewNotifier(),
13 | );
14 |
15 | class SubscriptionViewNotifier extends StateNotifier {
16 | SubscriptionViewNotifier() : super(const SubscriptionState()) {
17 | _setData();
18 | }
19 |
20 | void _setData() {
21 | final plans = [
22 | const SubscriptionPlan(
23 | id: freePlan,
24 | name: "Free",
25 | planDetail: "100 call/month",
26 | planInfo: "Basic plan"),
27 | const SubscriptionPlan(
28 | id: proPlan,
29 | name: "Pro",
30 | planDetail: "\u{20B9}200 /month",
31 | planInfo: "Unlimited or higher threshold")
32 | ];
33 | state = state.copyWith(plans: plans, selectedPlan: plans.first);
34 | }
35 |
36 | void onSelectPlan(SubscriptionPlan plan) {
37 | state = state.copyWith(selectedPlan: plan);
38 | }
39 | }
40 |
41 | @freezed
42 | class SubscriptionState with _$SubscriptionState {
43 | const factory SubscriptionState({
44 | @Default(false) bool loading,
45 | SubscriptionPlan? selectedPlan,
46 | @Default([]) List plans,
47 | }) = _SubscriptionState;
48 | }
49 |
--------------------------------------------------------------------------------
/app/lib/ui/flow/space/create/create_space_view_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:data/log/logger.dart';
2 | import 'package:data/service/space_service.dart';
3 | import 'package:flutter/cupertino.dart';
4 | import 'package:flutter_riverpod/flutter_riverpod.dart';
5 | import 'package:freezed_annotation/freezed_annotation.dart';
6 |
7 | part 'create_space_view_model.freezed.dart';
8 |
9 | final createSpaceViewStateProvider = StateNotifierProvider.autoDispose<
10 | CreateSpaceViewNotifier, CreateSpaceViewState>((ref) {
11 | return CreateSpaceViewNotifier(
12 | ref.read(spaceServiceProvider),
13 | );
14 | });
15 |
16 | class CreateSpaceViewNotifier extends StateNotifier {
17 | final SpaceService spaceService;
18 |
19 | CreateSpaceViewNotifier(this.spaceService)
20 | : super(
21 | CreateSpaceViewState(spaceName: TextEditingController()),
22 | );
23 |
24 | Future createSpace() async {
25 | try {
26 | state = state.copyWith(isCreating: true, invitationCode: '', error: null);
27 | final invitationCode =
28 | await spaceService.createSpaceAndGetInviteCode(state.spaceName.text);
29 | state = state.copyWith(isCreating: false, invitationCode: invitationCode);
30 | } catch (error, stack) {
31 | state = state.copyWith(error: error, isCreating: false);
32 | logger.e(
33 | 'CreateSpaceViewNotifier: $error - error while creating new space',
34 | error: error,
35 | stackTrace: stack,
36 | );
37 | }
38 | }
39 |
40 | void updateSelectedSpaceName(String message) {
41 | if (message != state.selectedSpaceName) {
42 | state = state.copyWith(
43 | selectedSpaceName: message,
44 | spaceName: TextEditingController(text: message),
45 | allowSave: message.isNotEmpty,
46 | );
47 | } else {
48 | state = state.copyWith(
49 | selectedSpaceName: '',
50 | spaceName: TextEditingController(text: ''),
51 | allowSave: false);
52 | }
53 | }
54 |
55 | void onChange() {
56 | state = state.copyWith(allowSave: state.spaceName.text.isNotEmpty);
57 | }
58 |
59 | @override
60 | void dispose() {
61 | state.spaceName.dispose();
62 | super.dispose();
63 | }
64 | }
65 |
66 | @freezed
67 | class CreateSpaceViewState with _$CreateSpaceViewState {
68 | const factory CreateSpaceViewState({
69 | @Default(false) bool allowSave,
70 | @Default(false) bool isCreating,
71 | @Default('') String selectedSpaceName,
72 | @Default('') String invitationCode,
73 | required TextEditingController spaceName,
74 | Object? error,
75 | }) = _CreateSpaceViewState;
76 | }
77 |
--------------------------------------------------------------------------------
/build_watch:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 |
4 | function cleanup {
5 | pkill -P $$
6 | }
7 | trap cleanup EXIT
8 |
9 | # Function to keep running a command until it succeeds
10 | function keep_running {
11 | while true; do
12 | dart run build_runner watch --delete-conflicting-outputs;
13 | echo "Command failed with no zero exit code. Respawning.."
14 | sleep 1
15 | done
16 | }
17 |
18 | # Navigate to each project directory and run the watcher in the background
19 | (cd app && keep_running) &
20 | (cd data && keep_running) &
21 |
22 | # Wait for all background processes to finish
23 | wait
24 |
--------------------------------------------------------------------------------
/data/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
26 | /pubspec.lock
27 | **/doc/api/
28 | .dart_tool/
29 | build/
30 | .flutter-plugins
31 | .flutter-plugins-dependencies
32 |
33 | # Config file
34 | ./lib/config.dart
35 |
--------------------------------------------------------------------------------
/data/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: "41456452f29d64e8deb623a3c927524bcf9f111b"
8 | channel: "stable"
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/data/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.0.1
2 |
3 | * TODO: Describe initial release.
4 |
--------------------------------------------------------------------------------
/data/LICENSE:
--------------------------------------------------------------------------------
1 | TODO: Add your license here.
2 |
--------------------------------------------------------------------------------
/data/README.md:
--------------------------------------------------------------------------------
1 | # Data
2 |
3 | The YourSpace data module is the central hub for managing all data operations within the YourSpace
4 | app. This module efficiently handles both local storage and remote data, ensuring a smooth and
5 | consistent flow of information. It provides services for creating, reading, updating, and deleting (
6 | CRUD) data across Firebase and local databases (SQLite).
7 |
8 | ## Features
9 |
10 | - **Data Operations:** Supports full CRUD operations for data stored locally and remotely, enabling flexible data handling and synchronization.
11 | - **Data Sources:** Integrates with Firebase services for real-time data synchronization and cloud storage.
12 |
13 | ### API
14 |
15 | - **Service:** Manages data operations and provides methods for data retrieval and updates.
16 | - **Data Models:** Defines all the data classes used in the app.
--------------------------------------------------------------------------------
/data/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | analyzer:
2 | errors:
3 | depend_on_referenced_packages: ignore
4 | non_constant_identifier_names: ignore
5 | include: package:flutter_lints/flutter.yaml
6 |
7 | # Additional information about this file can be found at
8 | # https://dart.dev/guides/language/analysis-options
9 |
--------------------------------------------------------------------------------
/data/build.yaml:
--------------------------------------------------------------------------------
1 | targets:
2 | $default:
3 | builders:
4 | json_serializable:
5 | options:
6 | explicit_to_json: true
--------------------------------------------------------------------------------
/data/lib/api/location/journey/journey.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'journey.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | _$LocationJourneyImpl _$$LocationJourneyImplFromJson(
10 | Map json) =>
11 | _$LocationJourneyImpl(
12 | id: json['id'] as String?,
13 | user_id: json['user_id'] as String,
14 | from_latitude: (json['from_latitude'] as num).toDouble(),
15 | from_longitude: (json['from_longitude'] as num).toDouble(),
16 | to_latitude: (json['to_latitude'] as num?)?.toDouble(),
17 | to_longitude: (json['to_longitude'] as num?)?.toDouble(),
18 | routes: (json['routes'] as List?)
19 | ?.map((e) => JourneyRoute.fromJson(e as Map))
20 | .toList() ??
21 | const [],
22 | route_distance: (json['route_distance'] as num?)?.toDouble(),
23 | route_duration: (json['route_duration'] as num?)?.toInt(),
24 | created_at: (json['created_at'] as num?)?.toInt(),
25 | update_at: (json['update_at'] as num?)?.toInt(),
26 | type: json['type'] as String?,
27 | );
28 |
29 | Map _$$LocationJourneyImplToJson(
30 | _$LocationJourneyImpl instance) =>
31 | {
32 | 'id': instance.id,
33 | 'user_id': instance.user_id,
34 | 'from_latitude': instance.from_latitude,
35 | 'from_longitude': instance.from_longitude,
36 | 'to_latitude': instance.to_latitude,
37 | 'to_longitude': instance.to_longitude,
38 | 'routes': instance.routes.map((e) => e.toJson()).toList(),
39 | 'route_distance': instance.route_distance,
40 | 'route_duration': instance.route_duration,
41 | 'created_at': instance.created_at,
42 | 'update_at': instance.update_at,
43 | 'type': instance.type,
44 | };
45 |
46 | _$JourneyRouteImpl _$$JourneyRouteImplFromJson(Map json) =>
47 | _$JourneyRouteImpl(
48 | latitude: (json['latitude'] as num).toDouble(),
49 | longitude: (json['longitude'] as num).toDouble(),
50 | );
51 |
52 | Map _$$JourneyRouteImplToJson(_$JourneyRouteImpl instance) =>
53 | {
54 | 'latitude': instance.latitude,
55 | 'longitude': instance.longitude,
56 | };
57 |
--------------------------------------------------------------------------------
/data/lib/api/location/location.dart:
--------------------------------------------------------------------------------
1 | //ignore_for_file: constant_identifier_names
2 |
3 | import 'package:cloud_firestore/cloud_firestore.dart';
4 | import 'package:freezed_annotation/freezed_annotation.dart';
5 | import 'package:geolocator/geolocator.dart';
6 | import 'package:google_maps_flutter/google_maps_flutter.dart';
7 |
8 | part 'location.freezed.dart';
9 | part 'location.g.dart';
10 |
11 | const USER_STATE_STEADY = 0;
12 | const USER_STATE_MOVING = 1;
13 |
14 | @freezed
15 | class ApiLocation with _$ApiLocation {
16 | const ApiLocation._();
17 |
18 | const factory ApiLocation({
19 | required String id,
20 | required String user_id,
21 | required double latitude,
22 | required double longitude,
23 | int? user_state,
24 | int? created_at,
25 | }) = _ApiLocation;
26 |
27 | factory ApiLocation.fromJson(Map data) =>
28 | _$ApiLocationFromJson(data);
29 |
30 | factory ApiLocation.fromFireStore(
31 | DocumentSnapshot