From 489aee22813c1f9d432dc2ce098dfe5a0e7c3467 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 10 Jun 2024 19:23:18 +0530 Subject: [PATCH 01/65] Fix map view --- app/android/app/build.gradle | 2 + app/android/app/src/main/AndroidManifest.xml | 9 + app/assets/images/ic_30_battery_icon.svg | 8 + app/assets/images/ic_50_battery_icon.svg | 8 + app/assets/images/ic_add_user_icon.svg | 8 + app/assets/images/ic_down_arrow_icon.svg | 5 + app/assets/images/ic_empty_battery_icon.svg | 8 + app/assets/images/ic_full_bettery_icon.svg | 8 + app/assets/images/ic_geofence_icon.svg | 5 + app/assets/images/ic_relocate_icon.svg | 5 + .../images/ic_time_line_history_icon.svg | 8 + app/assets/locales/app_en.arb | 18 +- app/assets/map/map_theme_night.json | 161 +++++++++++++ .../extenstions/lat_lng_extenstion.dart | 34 +++ app/lib/gen/assets.gen.dart | 48 ++++ .../ui/components/user_battery_status.dart | 50 ++++ app/lib/ui/components/user_profile_image.dart | 48 ++++ .../ui/flow/home/components/home_top_bar.dart | 104 +++++---- app/lib/ui/flow/home/components/map_view.dart | 18 -- .../home/components/space_user_footer.dart | 199 +++++++++++++++- app/lib/ui/flow/home/home_screen.dart | 39 +++- .../ui/flow/home/home_screen_viewmodel.dart | 39 +++- .../home/home_screen_viewmodel.freezed.dart | 39 +++- .../selected_member_detail_view.dart | 221 ++++++++++++++++++ app/lib/ui/flow/home/map/map_view.dart | 44 ++++ app/lib/ui/flow/home/map/map_view_model.dart | 38 +++ app/lib/ui/flow/setting/setting_screen.dart | 1 + app/pubspec.lock | 64 +++++ app/pubspec.yaml | 5 + data/lib/api/auth/auth_models.dart | 27 ++- data/lib/api/auth/auth_models.freezed.dart | 42 ++-- data/lib/api/auth/auth_models.g.dart | 4 +- style/lib/button/icon_primary_button.dart | 13 +- 33 files changed, 1192 insertions(+), 138 deletions(-) create mode 100644 app/assets/images/ic_30_battery_icon.svg create mode 100644 app/assets/images/ic_50_battery_icon.svg create mode 100644 app/assets/images/ic_add_user_icon.svg create mode 100644 app/assets/images/ic_down_arrow_icon.svg create mode 100644 app/assets/images/ic_empty_battery_icon.svg create mode 100644 app/assets/images/ic_full_bettery_icon.svg create mode 100644 app/assets/images/ic_geofence_icon.svg create mode 100644 app/assets/images/ic_relocate_icon.svg create mode 100644 app/assets/images/ic_time_line_history_icon.svg create mode 100644 app/assets/map/map_theme_night.json create mode 100644 app/lib/domain/extenstions/lat_lng_extenstion.dart create mode 100644 app/lib/ui/components/user_battery_status.dart create mode 100644 app/lib/ui/components/user_profile_image.dart delete mode 100644 app/lib/ui/flow/home/components/map_view.dart create mode 100644 app/lib/ui/flow/home/map/components/selected_member_detail_view.dart create mode 100644 app/lib/ui/flow/home/map/map_view.dart create mode 100644 app/lib/ui/flow/home/map/map_view_model.dart diff --git a/app/android/app/build.gradle b/app/android/app/build.gradle index bab78285..2761a282 100644 --- a/app/android/app/build.gradle +++ b/app/android/app/build.gradle @@ -2,6 +2,7 @@ plugins { id "com.android.application" id "kotlin-android" id "dev.flutter.flutter-gradle-plugin" + id "com.google.gms.google-services" } def localProperties = new Properties() @@ -51,6 +52,7 @@ android { versionName flutterVersionName multiDexEnabled true + manifestPlaceholders += [MAPS_API_KEY: localProperties.getProperty('MAPS_API_KEY')] } signingConfigs { diff --git a/app/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml index bdc77d9c..e16638af 100644 --- a/app/android/app/src/main/AndroidManifest.xml +++ b/app/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,9 @@ + + + + + + + + + + diff --git a/app/assets/images/ic_50_battery_icon.svg b/app/assets/images/ic_50_battery_icon.svg new file mode 100644 index 00000000..7f7def82 --- /dev/null +++ b/app/assets/images/ic_50_battery_icon.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/images/ic_add_user_icon.svg b/app/assets/images/ic_add_user_icon.svg new file mode 100644 index 00000000..bccdb70d --- /dev/null +++ b/app/assets/images/ic_add_user_icon.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/images/ic_down_arrow_icon.svg b/app/assets/images/ic_down_arrow_icon.svg new file mode 100644 index 00000000..823009cb --- /dev/null +++ b/app/assets/images/ic_down_arrow_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/images/ic_empty_battery_icon.svg b/app/assets/images/ic_empty_battery_icon.svg new file mode 100644 index 00000000..a45ad42b --- /dev/null +++ b/app/assets/images/ic_empty_battery_icon.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/images/ic_full_bettery_icon.svg b/app/assets/images/ic_full_bettery_icon.svg new file mode 100644 index 00000000..e076a626 --- /dev/null +++ b/app/assets/images/ic_full_bettery_icon.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/images/ic_geofence_icon.svg b/app/assets/images/ic_geofence_icon.svg new file mode 100644 index 00000000..332061e7 --- /dev/null +++ b/app/assets/images/ic_geofence_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/images/ic_relocate_icon.svg b/app/assets/images/ic_relocate_icon.svg new file mode 100644 index 00000000..9d9d493b --- /dev/null +++ b/app/assets/images/ic_relocate_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/images/ic_time_line_history_icon.svg b/app/assets/images/ic_time_line_history_icon.svg new file mode 100644 index 00000000..da071a7f --- /dev/null +++ b/app/assets/images/ic_time_line_history_icon.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/locales/app_en.arb b/app/assets/locales/app_en.arb index 826ec600..a0c531b8 100644 --- a/app/assets/locales/app_en.arb +++ b/app/assets/locales/app_en.arb @@ -1,9 +1,7 @@ { "app_title": "YourSpace", "app_tag_line": "Stay Close, Anywhere!", - "alert_confirm_default_title": "Are you sure", - "@_COMMON": { }, "common_get_started": "Get Started", @@ -12,22 +10,22 @@ "common_cancel": "Cancel", "common_delete": "Delete", "common_okay": "Okay", - "common_verify": "Verify","commonMembers": "{memberCount} {memberCount, plural, =1{Member} other{Members}}", + "common_add": "Add", + "common_verify": "Verify", + "commonMembers": "{memberCount} {memberCount, plural, =1{Member} other{Members}}", "@commonMembers": { "placeholders": { "memberCount": {} } }, - - "@_INTRO":{ - }, + "@_INTRO": { + }, "intro_1_title": "Live location", "intro_2_title": "Receive alerts", "intro_3_title": "Location history", - "intro_1_subTitle": "Share your location seamlessly, connecting with just a click.", - "intro_2_subTitle": "Stay in the know with instant alerts – whether loved ones enter or leave.", - "intro_3_subTitle": "Simplify your connections and insights – explore drive reports, location history effortlessly.", - + "intro_1_subTitle": "Share your location seamlessly, connecting with just a click.", + "intro_2_subTitle": "Stay in the know with instant alerts – whether loved ones enter or leave.", + "intro_3_subTitle": "Simplify your connections and insights – explore drive reports, location history effortlessly.", "@_AUTH": { }, "sign_in_options_continue_with_google_btn_title": "Continue with Google", diff --git a/app/assets/map/map_theme_night.json b/app/assets/map/map_theme_night.json new file mode 100644 index 00000000..049e2138 --- /dev/null +++ b/app/assets/map/map_theme_night.json @@ -0,0 +1,161 @@ +[ + { + "elementType": "geometry", + "stylers": [ + { + "color": "#242f3e" + } + ] + }, + { + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#746855" + } + ] + }, + { + "elementType": "labels.text.stroke", + "stylers": [ + { + "color": "#242f3e" + } + ] + }, + { + "featureType": "administrative.locality", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#d59563" + } + ] + }, + { + "featureType": "poi", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#d59563" + } + ] + }, + { + "featureType": "poi.park", + "elementType": "geometry", + "stylers": [ + { + "color": "#263c3f" + } + ] + }, + { + "featureType": "poi.park", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#6b9a76" + } + ] + }, + { + "featureType": "road", + "elementType": "geometry", + "stylers": [ + { + "color": "#38414e" + } + ] + }, + { + "featureType": "road", + "elementType": "geometry.stroke", + "stylers": [ + { + "color": "#212a37" + } + ] + }, + { + "featureType": "road", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#9ca5b3" + } + ] + }, + { + "featureType": "road.highway", + "elementType": "geometry", + "stylers": [ + { + "color": "#746855" + } + ] + }, + { + "featureType": "road.highway", + "elementType": "geometry.stroke", + "stylers": [ + { + "color": "#1f2835" + } + ] + }, + { + "featureType": "road.highway", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#f3d19c" + } + ] + }, + { + "featureType": "transit", + "elementType": "geometry", + "stylers": [ + { + "color": "#2f3948" + } + ] + }, + { + "featureType": "transit.station", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#d59563" + } + ] + }, + { + "featureType": "water", + "elementType": "geometry", + "stylers": [ + { + "color": "#17263c" + } + ] + }, + { + "featureType": "water", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#515c6d" + } + ] + }, + { + "featureType": "water", + "elementType": "labels.text.stroke", + "stylers": [ + { + "color": "#17263c" + } + ] + } +] \ No newline at end of file diff --git a/app/lib/domain/extenstions/lat_lng_extenstion.dart b/app/lib/domain/extenstions/lat_lng_extenstion.dart new file mode 100644 index 00000000..69e5a48d --- /dev/null +++ b/app/lib/domain/extenstions/lat_lng_extenstion.dart @@ -0,0 +1,34 @@ +import 'package:data/log/logger.dart'; +import 'package:geocoding/geocoding.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +extension LatLngExtensions on LatLng { + Future getAddressFromLocation() async { + String? address = ''; + try { + final placeMarks = await placemarkFromCoordinates(latitude, longitude); + if (placeMarks.isNotEmpty) { + var streets = placeMarks + .map((placeMark) => placeMark.street) + .where((street) => street != null); + + streets = streets.where((street) => + street!.toLowerCase() != placeMarks.last.locality!.toLowerCase()); + + streets = streets.where((street) => !street!.contains('+')); + address += streets.join(', '); + + address += ', ${placeMarks.reversed.last.subLocality ?? ''}'; + address += ', ${placeMarks.reversed.last.locality ?? ''}'; + address += ', ${placeMarks.reversed.last.subAdministrativeArea ?? ''}'; + address += ', ${placeMarks.reversed.last.administrativeArea ?? ''}'; + address += ', ${placeMarks.reversed.last.postalCode ?? ''}'; + address += ', ${placeMarks.reversed.last.country ?? ''}'; + } + return address; + } catch (e) { + logger.e('GetAddress: Error while getting address', error: e); + } + return ''; + } +} diff --git a/app/lib/gen/assets.gen.dart b/app/lib/gen/assets.gen.dart index 2c4a2d40..f65bc03f 100644 --- a/app/lib/gen/assets.gen.dart +++ b/app/lib/gen/assets.gen.dart @@ -16,18 +16,39 @@ class $AssetsImagesGen { AssetGenImage get appLogo => const AssetGenImage('assets/images/app_logo.png'); + /// File path: assets/images/ic_30_battery_icon.svg + String get ic30BatteryIcon => 'assets/images/ic_30_battery_icon.svg'; + + /// File path: assets/images/ic_50_battery_icon.svg + String get ic50BatteryIcon => 'assets/images/ic_50_battery_icon.svg'; + /// File path: assets/images/ic_about_us.svg String get icAboutUs => 'assets/images/ic_about_us.svg'; /// File path: assets/images/ic_add_member.svg String get icAddMember => 'assets/images/ic_add_member.svg'; + /// File path: assets/images/ic_add_user_icon.svg + String get icAddUserIcon => 'assets/images/ic_add_user_icon.svg'; + /// File path: assets/images/ic_contact_support.svg String get icContactSupport => 'assets/images/ic_contact_support.svg'; + /// File path: assets/images/ic_down_arrow_icon.svg + String get icDownArrowIcon => 'assets/images/ic_down_arrow_icon.svg'; + /// File path: assets/images/ic_edit_profile.svg String get icEditProfile => 'assets/images/ic_edit_profile.svg'; + /// File path: assets/images/ic_empty_battery_icon.svg + String get icEmptyBatteryIcon => 'assets/images/ic_empty_battery_icon.svg'; + + /// File path: assets/images/ic_full_bettery_icon.svg + String get icFullBetteryIcon => 'assets/images/ic_full_bettery_icon.svg'; + + /// File path: assets/images/ic_geofence_icon.svg + String get icGeofenceIcon => 'assets/images/ic_geofence_icon.svg'; + /// File path: assets/images/ic_google_logo.svg String get icGoogleLogo => 'assets/images/ic_google_logo.svg'; @@ -40,6 +61,9 @@ class $AssetsImagesGen { /// File path: assets/images/ic_privacy_policy.svg String get icPrivacyPolicy => 'assets/images/ic_privacy_policy.svg'; + /// File path: assets/images/ic_relocate_icon.svg + String get icRelocateIcon => 'assets/images/ic_relocate_icon.svg'; + /// File path: assets/images/ic_remove.svg String get icRemove => 'assets/images/ic_remove.svg'; @@ -49,6 +73,10 @@ class $AssetsImagesGen { /// File path: assets/images/ic_sign_out.svg String get icSignOut => 'assets/images/ic_sign_out.svg'; + /// File path: assets/images/ic_time_line_history_icon.svg + String get icTimeLineHistoryIcon => + 'assets/images/ic_time_line_history_icon.svg'; + /// File path: assets/images/intro_1.svg String get intro1 => 'assets/images/intro_1.svg'; @@ -65,17 +93,26 @@ class $AssetsImagesGen { /// List of all assets List get values => [ appLogo, + ic30BatteryIcon, + ic50BatteryIcon, icAboutUs, icAddMember, + icAddUserIcon, icContactSupport, + icDownArrowIcon, icEditProfile, + icEmptyBatteryIcon, + icFullBetteryIcon, + icGeofenceIcon, icGoogleLogo, icLocation, icMessage, icPrivacyPolicy, + icRelocateIcon, icRemove, icSetting, icSignOut, + icTimeLineHistoryIcon, intro1, intro2, intro3, @@ -83,10 +120,21 @@ class $AssetsImagesGen { ]; } +class $AssetsMapGen { + const $AssetsMapGen(); + + /// File path: assets/map/map_theme_night.json + String get mapThemeNight => 'assets/map/map_theme_night.json'; + + /// List of all assets + List get values => [mapThemeNight]; +} + class Assets { Assets._(); static const $AssetsImagesGen images = $AssetsImagesGen(); + static const $AssetsMapGen map = $AssetsMapGen(); } class AssetGenImage { diff --git a/app/lib/ui/components/user_battery_status.dart b/app/lib/ui/components/user_battery_status.dart new file mode 100644 index 00000000..0148731f --- /dev/null +++ b/app/lib/ui/components/user_battery_status.dart @@ -0,0 +1,50 @@ +import 'package:data/api/auth/auth_models.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/text/app_text_dart.dart'; + +import '../../gen/assets.gen.dart'; + +class UserBatteryStatus extends StatelessWidget { + final ApiUserInfo userInfo; + + const UserBatteryStatus({super.key, required this.userInfo}); + + @override + Widget build(BuildContext context) { + final batteryPct = userInfo.session?.battery_pct ?? 0; + String icon; + Color color; + + if (batteryPct > 70.0) { + icon = Assets.images.icFullBetteryIcon; + color = context.colorScheme.positive; + } else if (batteryPct > 50.0) { + icon = Assets.images.ic50BatteryIcon; + color = context.colorScheme.positive; + } else if (batteryPct > 30.0) { + icon = Assets.images.ic30BatteryIcon; + color = context.colorScheme.positive; + } else { + icon = Assets.images.icEmptyBatteryIcon; + color = context.colorScheme.alert; + } + return Row( + children: [ + SvgPicture.asset( + icon, + colorFilter: ColorFilter.mode(color, BlendMode.srcATop), + ), + Text( + '$batteryPct%', + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textPrimary), + ) + ], + ); + } + + void getBatteryIcon() {} +} diff --git a/app/lib/ui/components/user_profile_image.dart b/app/lib/ui/components/user_profile_image.dart new file mode 100644 index 00000000..1e10b87b --- /dev/null +++ b/app/lib/ui/components/user_profile_image.dart @@ -0,0 +1,48 @@ +import 'package:flutter/cupertino.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/text/app_text_dart.dart'; + +class ImageAvatar extends StatelessWidget { + final String? imageUrl; + final double size; + final String initials; + final Color? backgroundColor; + final Color? foregroundColor; + + const ImageAvatar({ + super.key, + this.imageUrl, + this.size = 48, + this.initials = '', + this.backgroundColor, + this.foregroundColor, + }); + + @override + Widget build(BuildContext context) { + final image = imageUrl ?? ''; + return Container( + width: size, + height: size, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: backgroundColor ?? context.colorScheme.primary, + borderRadius: BorderRadius.circular(size), + ), + child: image.isEmpty + ? Center( + child: Text( + initials, + style: AppTextStyle.header2.copyWith( + fontSize: size * 0.4, + color: foregroundColor ?? context.colorScheme.onPrimary, + ), + ), + ) + : Image.network( + imageUrl!, + fit: BoxFit.cover, + ), + ); + } +} diff --git a/app/lib/ui/flow/home/components/home_top_bar.dart b/app/lib/ui/flow/home/components/home_top_bar.dart index 7f3f8f38..9dc68451 100644 --- a/app/lib/ui/flow/home/components/home_top_bar.dart +++ b/app/lib/ui/flow/home/components/home_top_bar.dart @@ -74,58 +74,60 @@ class _HomeTopBarState extends State with TickerProviderStateMixin { } Widget _body(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: _topBar(context), - ); + return _topBar(context); } Widget _topBar(BuildContext context) { return IntrinsicHeight( child: Container( - color: expand ? context.colorScheme.surface : null, + color: context.colorScheme.surface, child: SingleChildScrollView( - child: Column( - children: [ - Row( - children: [ - _iconButton( - context: context, - icon: Assets.images.icSetting, - visibility: !expand, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16,vertical: 12), + child: Column( + children: [ + Row( + children: [ + _iconButton( + context: context, + icon: Assets.images.icSetting, + visibility: !expand, onTap: () { AppRoute.setting.push(context); - }), - const SizedBox(width: 8), - _spaceSelection( - context: context, - spaceName: widget.selectedSpace?.space.name ?? context.l10n.home_select_space_text, - ), - const SizedBox(width: 8), - _iconButton( - context: context, - icon: Assets.images.icMessage, - visibility: !expand, - onTap: () {}, - ), - SizedBox(width: expand ? 0 : 8), - _iconButton( - context: context, - icon: Assets.images.icLocation, - visibility: !expand, - onTap: () {}, - ), - _iconButton( - context: context, - icon: Assets.images.icAddMember, - visibility: expand, - color: context.colorScheme.textPrimary, - onTap: () => widget.onAddMemberTap(), - ), - ], - ), - _dropDown(context), - ], + }, + ), + const SizedBox(width: 8), + _spaceSelection( + context: context, + spaceName: widget.selectedSpace?.space.name ?? + context.l10n.home_select_space_text, + ), + const SizedBox(width: 8), + _iconButton( + context: context, + icon: Assets.images.icMessage, + visibility: !expand, + onTap: () {}, + ), + SizedBox(width: expand ? 0 : 8), + _iconButton( + context: context, + icon: Assets.images.icLocation, + visibility: !expand, + onTap: () {}, + ), + _iconButton( + context: context, + icon: Assets.images.icAddMember, + visibility: expand, + color: context.colorScheme.textPrimary, + onTap: () => widget.onAddMemberTap(), + ), + ], + ), + _dropDown(context), + ], + ), ), ), ), @@ -146,6 +148,7 @@ class _HomeTopBarState extends State with TickerProviderStateMixin { }, child: Container( decoration: BoxDecoration( + color: context.colorScheme.surface, border: Border.all( color: context.colorScheme.outline, width: 1, @@ -165,13 +168,16 @@ class _HomeTopBarState extends State with TickerProviderStateMixin { .copyWith(color: context.colorScheme.textPrimary), ), ), - if (widget.fetchingInviteCode || (widget.selectedSpace == null && widget.spaces.isNotEmpty)) ...[ - const AppProgressIndicator(size: AppProgressIndicatorSize.small) + const Spacer(), + if (widget.fetchingInviteCode || + (widget.selectedSpace == null && widget.spaces.isNotEmpty)) ...[ + const AppProgressIndicator( + size: AppProgressIndicatorSize.small) ] else ...[ Icon( expand - ? Icons.keyboard_arrow_down_rounded - : Icons.keyboard_arrow_up_rounded, + ? Icons.keyboard_arrow_up_rounded + : Icons.keyboard_arrow_down_rounded, color: context.colorScheme.textPrimary, ), ], @@ -194,7 +200,6 @@ class _HomeTopBarState extends State with TickerProviderStateMixin { visible: visibility, child: IconPrimaryButton( onTap: () => onTap(), - radius: 20, icon: SvgPicture.asset( height: 16, width: 14, @@ -284,7 +289,6 @@ class _HomeTopBarState extends State with TickerProviderStateMixin { style: AppTextStyle.subtitle2.copyWith( color: context.colorScheme.textPrimary, ), - overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), Row( diff --git a/app/lib/ui/flow/home/components/map_view.dart b/app/lib/ui/flow/home/components/map_view.dart deleted file mode 100644 index 26f903f9..00000000 --- a/app/lib/ui/flow/home/components/map_view.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -class MapView extends ConsumerStatefulWidget { - const MapView({super.key}); - - @override - ConsumerState createState() => _MapScreenState(); -} - -class _MapScreenState extends ConsumerState { - @override - Widget build(BuildContext context) { - return const Center( - child: Text("Hello, Map 123"), - ); - } -} diff --git a/app/lib/ui/flow/home/components/space_user_footer.dart b/app/lib/ui/flow/home/components/space_user_footer.dart index fe10aff5..0b705645 100644 --- a/app/lib/ui/flow/home/components/space_user_footer.dart +++ b/app/lib/ui/flow/home/components/space_user_footer.dart @@ -1,10 +1,205 @@ +import 'package:data/api/auth/auth_models.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:style/animation/on_tap_scale.dart'; +import 'package:style/button/icon_primary_button.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; + +import '../../../../gen/assets.gen.dart'; +import '../../../components/user_profile_image.dart'; +import '../map/components/selected_member_detail_view.dart'; class SpaceUserFooter extends StatelessWidget { - const SpaceUserFooter({super.key}); + final List? members; + final ApiUserInfo? selectedMember; + final void Function() onAddMemberTap; + final void Function(ApiUserInfo) onMemberTap; + final void Function() onRelocateTap; + final void Function() onPlacesTap; + final void Function() onDismiss; + final void Function() onTapTimeline; + + const SpaceUserFooter({ + super.key, + required this.members, + this.selectedMember, + required this.onAddMemberTap, + required this.onMemberTap, + required this.onRelocateTap, + required this.onPlacesTap, + required this.onDismiss, + required this.onTapTimeline, + }); @override Widget build(BuildContext context) { - return const Placeholder(); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16), + child: Column( + children: [ + _mapControlBtn(context), + SelectedMemberDetailView( + userInfo: selectedMember, + onDismiss: () => onDismiss(), + onTapTimeline: () => onTapTimeline(), + ), + Visibility( + visible: members != null && members!.isNotEmpty, + child: + selectedSpaceMemberView(context: context, members: members)), + ], + ), + ); + } + + Widget _mapControlBtn(BuildContext context) { + return SizedBox( + width: context.mediaQuerySize.width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + _iconButton( + context: context, + icon: Assets.images.icRelocateIcon, + iconSize: 24, + foreground: context.colorScheme.primary, + background: context.colorScheme.surface, + visibility: true, + onTap: () => onRelocateTap, + ), + const SizedBox(height: 8), + _iconButton( + context: context, + icon: Assets.images.icGeofenceIcon, + iconSize: 24, + foreground: context.colorScheme.onPrimary, + background: context.colorScheme.primary, + visibility: true, + onTap: () => onPlacesTap, + ) + ], + ), + ); + } + + Widget _iconButton({ + required BuildContext context, + required String icon, + required double iconSize, + required Color foreground, + required Color background, + required bool visibility, + required Function() onTap, + }) { + return Visibility( + visible: visibility, + child: IconPrimaryButton( + backgroundColor: background, + onTap: () => onTap(), + icon: SvgPicture.asset( + icon, + colorFilter: ColorFilter.mode( + foreground, + BlendMode.srcATop, + ), + ), + ), + ); + } + + Widget selectedSpaceMemberView({ + required BuildContext context, + required List? members, + }) { + if (members == null || members.isEmpty) return Container(); + return Container( + padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + color: context.colorScheme.surface), + child: Wrap( + alignment: WrapAlignment.center, + children: [ + addMemberView(context), + ...members.map((item) => spaceMemberItem(context, item)), + ], + ), + ); + } + + Widget addMemberView(BuildContext context) { + return OnTapScale( + onTap: () => onAddMemberTap(), + child: Padding( + padding: const EdgeInsets.only(right: 6), + child: Column( + children: [ + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + border: + Border.all(color: context.colorScheme.primary, width: 1), + borderRadius: BorderRadius.circular(30)), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: SvgPicture.asset( + Assets.images.icAddUserIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.primary, + BlendMode.srcATop, + ), + ), + ), + ), + const SizedBox(height: 2), + Text( + context.l10n.common_add, + maxLines: 1, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textPrimary), + ), + ], + ), + ), + ); + } + + Widget spaceMemberItem( + BuildContext context, + ApiUserInfo userInfo, + ) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 6), + child: OnTapScale( + onTap: () { + onMemberTap(userInfo); + }, + child: SizedBox( + width: 40, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ImageAvatar( + size: 40, + imageUrl: userInfo.user.profile_image, + initials: userInfo.user.firstChar, + ), + const SizedBox(height: 2), + Text( + userInfo.user.first_name ?? '', + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textPrimary), + ) + ], + ), + ), + ), + ); } } diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index 044a4d58..c414bd6e 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -9,7 +9,8 @@ import 'package:yourspace_flutter/ui/components/resume_detector.dart'; import 'package:yourspace_flutter/ui/flow/home/home_screen_viewmodel.dart'; import 'components/home_top_bar.dart'; -import 'components/map_view.dart'; +import 'components/space_user_footer.dart'; +import 'map/map_view.dart'; class HomeScreen extends ConsumerStatefulWidget { const HomeScreen({super.key}); @@ -60,23 +61,43 @@ class _HomeScreenState extends ConsumerState { loading: state.loading, fetchingInviteCode: state.fetchingInviteCode, ), - // SpaceUserFooter() + Positioned( + bottom: 0, + left: 0, + right: 0, + child: SpaceUserFooter( + members: state.selectedSpace?.members, + selectedMember: state.selectedMember, + onAddMemberTap: () => notifier.onAddMemberTap(), + onMemberTap: (member) { + notifier.onSelectMember(member); + }, + onRelocateTap: () {}, + onPlacesTap: () {}, + onDismiss: () => notifier.onDismissMemberDetail(), + onTapTimeline: () {}, + ), + ), ], ), ); } void _observeNavigation(HomeViewState state) { - ref.listen(homeViewStateProvider.select((state) => state.spaceInvitationCode), - (_, next) { - if (next.isNotEmpty) { - AppRoute.inviteCode(code: next, spaceName: state.selectedSpace?.space.name ?? '').push(context); - } - }); + ref.listen( + homeViewStateProvider.select((state) => state.spaceInvitationCode), + (_, next) { + if (next.isNotEmpty) { + AppRoute.inviteCode( + code: next, spaceName: state.selectedSpace?.space.name ?? '') + .push(context); + } + }); } void _observeError() { - ref.listen(homeViewStateProvider.select((state) => state.error), (previous, next) { + ref.listen(homeViewStateProvider.select((state) => state.error), + (previous, next) { if (next != null) { showErrorSnackBar(context, next.toString()); } diff --git a/app/lib/ui/flow/home/home_screen_viewmodel.dart b/app/lib/ui/flow/home/home_screen_viewmodel.dart index b0a9b77e..a069b8e4 100644 --- a/app/lib/ui/flow/home/home_screen_viewmodel.dart +++ b/app/lib/ui/flow/home/home_screen_viewmodel.dart @@ -1,17 +1,18 @@ +import 'package:data/api/auth/auth_models.dart'; import 'package:data/api/space/space_models.dart'; import 'package:data/log/logger.dart'; +import 'package:data/service/space_service.dart'; import 'package:data/storage/app_preferences.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:data/service/space_service.dart'; part 'home_screen_viewmodel.freezed.dart'; -final homeViewStateProvider = StateNotifierProvider.autoDispose< - HomeViewNotifier, HomeViewState>( - (ref) => HomeViewNotifier( - ref.read(spaceServiceProvider), - ref.read(currentUserSessionJsonPod.notifier), +final homeViewStateProvider = + StateNotifierProvider.autoDispose( + (ref) => HomeViewNotifier( + ref.read(spaceServiceProvider), + ref.read(currentUserSessionJsonPod.notifier), ), ); @@ -19,7 +20,8 @@ class HomeViewNotifier extends StateNotifier { final SpaceService spaceService; final StateController _currentSpaceIdController; - HomeViewNotifier(this.spaceService, this._currentSpaceIdController) : super(const HomeViewState()); + HomeViewNotifier(this.spaceService, this._currentSpaceIdController) + : super(const HomeViewState()); String? get currentSpaceId => _currentSpaceIdController.state; @@ -33,8 +35,10 @@ class HomeViewNotifier extends StateNotifier { final spaces = await spaceService.getAllSpaceInfo(); final sortedSpaces = spaces.toList(); + if (currentSpaceId != null) { - final selectedSpaceIndex = sortedSpaces.indexWhere((space) => space.space.id == currentSpaceId); + final selectedSpaceIndex = sortedSpaces + .indexWhere((space) => space.space.id == currentSpaceId); if (selectedSpaceIndex > -1) { final selectedSpace = sortedSpaces.removeAt(selectedSpaceIndex); sortedSpaces.insert(0, selectedSpace); @@ -59,9 +63,11 @@ class HomeViewNotifier extends StateNotifier { void onAddMemberTap() async { try { - state = state.copyWith(fetchingInviteCode: true); - final code = await spaceService.getInviteCode(state.selectedSpace?.space.id ?? ''); - state = state.copyWith(spaceInvitationCode: code ?? '', fetchingInviteCode: false); + state = state.copyWith(fetchingInviteCode: true, spaceInvitationCode: ''); + final code = + await spaceService.getInviteCode(state.selectedSpace?.space.id ?? ''); + state = state.copyWith( + spaceInvitationCode: code ?? '', fetchingInviteCode: false); } catch (error, stack) { state = state.copyWith(error: error, fetchingInviteCode: false); logger.e( @@ -78,6 +84,16 @@ class HomeViewNotifier extends StateNotifier { currentSpaceId = space.space.id; } } + + void onDismissMemberDetail() { + state = state.copyWith(selectedMember: null); + } + + void onSelectMember(ApiUserInfo member) { + final selectedMember = + (state.selectedMember?.user.id == member.user.id) ? null : member; + state = state.copyWith(selectedMember: selectedMember); + } } @freezed @@ -88,6 +104,7 @@ class HomeViewState with _$HomeViewState { @Default(false) bool loading, @Default(false) bool fetchingInviteCode, SpaceInfo? selectedSpace, + ApiUserInfo? selectedMember, @Default('') String spaceInvitationCode, @Default([]) List spaceList, Object? error, diff --git a/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart b/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart index 6fc49f77..a7bd013b 100644 --- a/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart +++ b/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart @@ -21,6 +21,7 @@ mixin _$HomeViewState { bool get loading => throw _privateConstructorUsedError; bool get fetchingInviteCode => throw _privateConstructorUsedError; SpaceInfo? get selectedSpace => throw _privateConstructorUsedError; + ApiUserInfo? get selectedMember => throw _privateConstructorUsedError; String get spaceInvitationCode => throw _privateConstructorUsedError; List get spaceList => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; @@ -42,11 +43,13 @@ abstract class $HomeViewStateCopyWith<$Res> { bool loading, bool fetchingInviteCode, SpaceInfo? selectedSpace, + ApiUserInfo? selectedMember, String spaceInvitationCode, List spaceList, Object? error}); $SpaceInfoCopyWith<$Res>? get selectedSpace; + $ApiUserInfoCopyWith<$Res>? get selectedMember; } /// @nodoc @@ -67,6 +70,7 @@ class _$HomeViewStateCopyWithImpl<$Res, $Val extends HomeViewState> Object? loading = null, Object? fetchingInviteCode = null, Object? selectedSpace = freezed, + Object? selectedMember = freezed, Object? spaceInvitationCode = null, Object? spaceList = null, Object? error = freezed, @@ -92,6 +96,10 @@ class _$HomeViewStateCopyWithImpl<$Res, $Val extends HomeViewState> ? _value.selectedSpace : selectedSpace // ignore: cast_nullable_to_non_nullable as SpaceInfo?, + selectedMember: freezed == selectedMember + ? _value.selectedMember + : selectedMember // ignore: cast_nullable_to_non_nullable + as ApiUserInfo?, spaceInvitationCode: null == spaceInvitationCode ? _value.spaceInvitationCode : spaceInvitationCode // ignore: cast_nullable_to_non_nullable @@ -115,6 +123,18 @@ class _$HomeViewStateCopyWithImpl<$Res, $Val extends HomeViewState> return _then(_value.copyWith(selectedSpace: value) as $Val); }); } + + @override + @pragma('vm:prefer-inline') + $ApiUserInfoCopyWith<$Res>? get selectedMember { + if (_value.selectedMember == null) { + return null; + } + + return $ApiUserInfoCopyWith<$Res>(_value.selectedMember!, (value) { + return _then(_value.copyWith(selectedMember: value) as $Val); + }); + } } /// @nodoc @@ -131,12 +151,15 @@ abstract class _$$HomeViewStateImplCopyWith<$Res> bool loading, bool fetchingInviteCode, SpaceInfo? selectedSpace, + ApiUserInfo? selectedMember, String spaceInvitationCode, List spaceList, Object? error}); @override $SpaceInfoCopyWith<$Res>? get selectedSpace; + @override + $ApiUserInfoCopyWith<$Res>? get selectedMember; } /// @nodoc @@ -155,6 +178,7 @@ class __$$HomeViewStateImplCopyWithImpl<$Res> Object? loading = null, Object? fetchingInviteCode = null, Object? selectedSpace = freezed, + Object? selectedMember = freezed, Object? spaceInvitationCode = null, Object? spaceList = null, Object? error = freezed, @@ -180,6 +204,10 @@ class __$$HomeViewStateImplCopyWithImpl<$Res> ? _value.selectedSpace : selectedSpace // ignore: cast_nullable_to_non_nullable as SpaceInfo?, + selectedMember: freezed == selectedMember + ? _value.selectedMember + : selectedMember // ignore: cast_nullable_to_non_nullable + as ApiUserInfo?, spaceInvitationCode: null == spaceInvitationCode ? _value.spaceInvitationCode : spaceInvitationCode // ignore: cast_nullable_to_non_nullable @@ -202,6 +230,7 @@ class _$HomeViewStateImpl implements _HomeViewState { this.loading = false, this.fetchingInviteCode = false, this.selectedSpace, + this.selectedMember, this.spaceInvitationCode = '', final List spaceList = const [], this.error}) @@ -222,6 +251,8 @@ class _$HomeViewStateImpl implements _HomeViewState { @override final SpaceInfo? selectedSpace; @override + final ApiUserInfo? selectedMember; + @override @JsonKey() final String spaceInvitationCode; final List _spaceList; @@ -238,7 +269,7 @@ class _$HomeViewStateImpl implements _HomeViewState { @override String toString() { - return 'HomeViewState(allowSave: $allowSave, isCreating: $isCreating, loading: $loading, fetchingInviteCode: $fetchingInviteCode, selectedSpace: $selectedSpace, spaceInvitationCode: $spaceInvitationCode, spaceList: $spaceList, error: $error)'; + return 'HomeViewState(allowSave: $allowSave, isCreating: $isCreating, loading: $loading, fetchingInviteCode: $fetchingInviteCode, selectedSpace: $selectedSpace, selectedMember: $selectedMember, spaceInvitationCode: $spaceInvitationCode, spaceList: $spaceList, error: $error)'; } @override @@ -255,6 +286,8 @@ class _$HomeViewStateImpl implements _HomeViewState { other.fetchingInviteCode == fetchingInviteCode) && (identical(other.selectedSpace, selectedSpace) || other.selectedSpace == selectedSpace) && + (identical(other.selectedMember, selectedMember) || + other.selectedMember == selectedMember) && (identical(other.spaceInvitationCode, spaceInvitationCode) || other.spaceInvitationCode == spaceInvitationCode) && const DeepCollectionEquality() @@ -270,6 +303,7 @@ class _$HomeViewStateImpl implements _HomeViewState { loading, fetchingInviteCode, selectedSpace, + selectedMember, spaceInvitationCode, const DeepCollectionEquality().hash(_spaceList), const DeepCollectionEquality().hash(error)); @@ -288,6 +322,7 @@ abstract class _HomeViewState implements HomeViewState { final bool loading, final bool fetchingInviteCode, final SpaceInfo? selectedSpace, + final ApiUserInfo? selectedMember, final String spaceInvitationCode, final List spaceList, final Object? error}) = _$HomeViewStateImpl; @@ -303,6 +338,8 @@ abstract class _HomeViewState implements HomeViewState { @override SpaceInfo? get selectedSpace; @override + ApiUserInfo? get selectedMember; + @override String get spaceInvitationCode; @override List get spaceList; diff --git a/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart b/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart new file mode 100644 index 00000000..0fc405dd --- /dev/null +++ b/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart @@ -0,0 +1,221 @@ +import 'package:data/api/auth/auth_models.dart'; +import 'package:data/api/location/location.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:style/animation/on_tap_scale.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/domain/extenstions/lat_lng_extenstion.dart'; + +import '../../../../../gen/assets.gen.dart'; +import '../../../../components/user_battery_status.dart'; +import '../../../../components/user_profile_image.dart'; + +class SelectedMemberDetailView extends StatefulWidget { + final ApiUserInfo? userInfo; + final void Function() onDismiss; + final void Function() onTapTimeline; + + const SelectedMemberDetailView({ + super.key, + required this.userInfo, + required this.onDismiss, + required this.onTapTimeline, + }); + + @override + State createState() => + _SelectedMemberDetailViewState(); +} + +class _SelectedMemberDetailViewState extends State { + @override + Widget build(BuildContext context) { + final userInfo = widget.userInfo; + return userInfo != null ? _userDetailCardView(userInfo) : Container(); + } + + Widget _userDetailCardView(ApiUserInfo userInfo) { + return Stack( + alignment: Alignment.topCenter, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: context.colorScheme.surface), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _userProfileView(userInfo), + const SizedBox(width: 16), + Expanded(child: _userDetailView(userInfo)), + ], + ), + ), + ), + + Container( + width: context.mediaQuerySize.width, + padding: const EdgeInsets.only(top: 24, right: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [_timeLineButtonView()], + ), + ), + + OnTapScale( + onTap: () => widget.onDismiss(), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: context.colorScheme.surface), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8), + child: SvgPicture.asset( + Assets.images.icDownArrowIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.textDisabled, BlendMode.srcATop), + ), + ), + ), + ), + ], + ); + } + + Widget _userProfileView(ApiUserInfo userInfo) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ImageAvatar( + imageUrl: userInfo.user.profile_image, + initials: userInfo.user.firstChar, + ), + const SizedBox(height: 2), + UserBatteryStatus(userInfo: userInfo) + ], + ); + } + + Widget _userDetailView(ApiUserInfo userInfo) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + userInfo.user.fullName, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ), + const SizedBox(height: 4), + Text( + 'Online', + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.positive), + ), + const SizedBox(height: 12), + _userAddressView(userInfo.location), + const SizedBox(height: 4), + _userTimeAgo(userInfo.user.created_at) + ], + ); + } + + Widget _userAddressView(ApiLocation? location) { + return FutureBuilder( + future: getAddress(location), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + final address = snapshot.data ?? ''; + return Text( + address, + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.textPrimary), + overflow: TextOverflow.ellipsis, + maxLines: 2, + ); + } else { + return const SizedBox(height: 16); + } + }, + ); + } + + Widget _timeLineButtonView() { + return OnTapScale( + onTap: () {}, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: context.colorScheme.containerLow), + padding: const EdgeInsets.all(8), + child: OnTapScale( + onTap: () => widget.onTapTimeline(), + child: SvgPicture.asset( + Assets.images.icTimeLineHistoryIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.textPrimary, + BlendMode.srcATop, + ), + ), + ), + ), + ); + } + + Widget _userTimeAgo(int? createdAt) { + final time = timeAgo(createdAt); + return Row( + children: [ + Icon( + Icons.access_time_outlined, + color: context.colorScheme.textDisabled, + size: 16, + ), + const SizedBox(width: 4), + Text( + time, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), + ) + ], + ); + } + + String timeAgo(int? timestamp) { + if (timestamp == null) return ""; + + final DateTime now = DateTime.now(); + final DateTime date = DateTime.fromMillisecondsSinceEpoch(timestamp); + + final Duration diff = now.difference(date); + + if (diff.inSeconds < 60) { + return "just now"; + } else if (diff.inMinutes < 60) { + return "${diff.inMinutes} minutes ago"; + } else if (diff.inHours < 24) { + return "${diff.inHours} hours ago"; + } else if (diff.inDays < 7) { + return "${diff.inDays} days ago"; + } else if (diff.inDays < 30) { + return "${diff.inDays ~/ 7} weeks ago"; + } else if (diff.inDays < 365) { + return "${diff.inDays ~/ 30} months ago"; + } else { + return "${diff.inDays ~/ 365} years ago"; + } + } + + Future getAddress(ApiLocation? location) async { + // if (location == null) return ''; + // test LatLng(21.231981, 72.8364215) + // LatLng(37.4219999, -122.0840575) + final latLng = LatLng(21.231981, 72.8364215); + final address = await latLng.getAddressFromLocation(); + return address; + } +} diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart new file mode 100644 index 00000000..347fba75 --- /dev/null +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -0,0 +1,44 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +const defaultCameraZoom = 15; +const defaultCameraZoomForSelectedUser = 17; + +class MapView extends ConsumerStatefulWidget { + + const MapView({super.key}); + + @override + ConsumerState createState() => _MapScreenState(); +} + +class _MapScreenState extends ConsumerState { + final Completer _controller = Completer(); + final _center = const LatLng(0.0, 0.0); + + void _onMapCreated(GoogleMapController controller) { + _controller.complete(controller); + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Center( + child: GoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: CameraPosition(target: _center, zoom: 5.0), + zoomControlsEnabled: false, + tiltGesturesEnabled: false, + myLocationButtonEnabled: false, + compassEnabled: false, + mapToolbarEnabled: false, + ), + ), + ], + ); + } +} diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart new file mode 100644 index 00000000..5b2712f1 --- /dev/null +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -0,0 +1,38 @@ +import 'package:data/api/auth/auth_models.dart'; +import 'package:data/storage/app_preferences.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'map_view_model.freezed.dart'; + +final mapViewStateProvider = + StateNotifierProvider.autoDispose((ref) { + final notifier = MapViewNotifier( + ref.read(currentUserSessionJsonPod.notifier), + ); + return notifier; +}); + +class MapViewNotifier extends StateNotifier { + final StateController _currentSpaceId; + + MapViewNotifier(this._currentSpaceId) : super(const MapViewState()) { + spaceId(_currentSpaceId.state); + } + + void spaceId(String? spaceId) { + print('XXX space id:${spaceId}'); + } + + void getSpaceMembersLocation() async { + + } +} + +@freezed +class MapViewState with _$MapViewState { + const factory MapViewState({ + ApiUserInfo? selectedMember, + Object? error, + }) = _MapViewState; +} diff --git a/app/lib/ui/flow/setting/setting_screen.dart b/app/lib/ui/flow/setting/setting_screen.dart index e0c83acb..ed85525e 100644 --- a/app/lib/ui/flow/setting/setting_screen.dart +++ b/app/lib/ui/flow/setting/setting_screen.dart @@ -256,6 +256,7 @@ class _SettingScreenState extends ConsumerState { return IconPrimaryButton( onTap: () {}, size: 36, + radius: 8, icon: SvgPicture.asset( height: 16, width: 14, diff --git a/app/pubspec.lock b/app/pubspec.lock index b4f14d5c..077aa6b8 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -620,6 +620,38 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + geocoding: + dependency: "direct main" + description: + name: geocoding + sha256: d580c801cba9386b4fac5047c4c785a4e19554f46be42f4f5e5b7deacd088a66 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + geocoding_android: + dependency: transitive + description: + name: geocoding_android + sha256: "1b13eca79b11c497c434678fed109c2be020b158cec7512c848c102bc7232603" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + geocoding_ios: + dependency: transitive + description: + name: geocoding_ios + sha256: "94ddba60387501bd1c11e18dca7c5a9e8c645d6e3da9c38b9762434941870c24" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + geocoding_platform_interface: + dependency: transitive + description: + name: geocoding_platform_interface + sha256: "8c2c8226e5c276594c2e18bfe88b19110ed770aeb7c1ab50ede570be8b92229b" + url: "https://pub.dev" + source: hosted + version: "3.2.0" glob: dependency: transitive description: @@ -644,6 +676,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1+1" + google_maps_flutter: + dependency: "direct main" + description: + name: google_maps_flutter + sha256: abefcb1e5e5c96bdd8084939dda555257af272c7972902ca46d5631092c1df68 + url: "https://pub.dev" + source: hosted + version: "2.2.8" + google_maps_flutter_android: + dependency: transitive + description: + name: google_maps_flutter_android + sha256: b9ddc35f8b55fd70a196e43a61594abce5c41bc0843ea078a97679a9791749fe + url: "https://pub.dev" + source: hosted + version: "2.9.0" + google_maps_flutter_ios: + dependency: transitive + description: + name: google_maps_flutter_ios + sha256: d2d63ae17297a5b045ec115572c5a86fa4e53bb6eceaa0c6d200ac5ca69bfca4 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + google_maps_flutter_platform_interface: + dependency: transitive + description: + name: google_maps_flutter_platform_interface + sha256: "2bf21aa97edba4461282af5de693b354e589d09f695f7a6f80437d084a29687e" + url: "https://pub.dev" + source: hosted + version: "2.7.1" google_sign_in: dependency: "direct main" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index daf36ed5..68614af3 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -55,6 +55,10 @@ dependencies: image_cropper: ^6.0.0 fluttertoast: ^8.2.6 + # map + google_maps_flutter: ^2.2.8 + geocoding: ^3.0.0 + # auth firebase_auth: ^4.20.0 firebase_core: ^2.23.0 @@ -93,6 +97,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/images/ + - assets/map/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware diff --git a/data/lib/api/auth/auth_models.dart b/data/lib/api/auth/auth_models.dart index 177f3e09..28a05a22 100644 --- a/data/lib/api/auth/auth_models.dart +++ b/data/lib/api/auth/auth_models.dart @@ -7,6 +7,7 @@ import 'package:data/api/location/location.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'auth_models.freezed.dart'; + part 'auth_models.g.dart'; const LOGIN_TYPE_GOOGLE = 1; @@ -50,23 +51,27 @@ class ApiUser with _$ApiUser { String get userNameFirstLetter { return first_name!.isNotEmpty ? first_name![0].toUpperCase() : ''; } + + String get firstChar { + final trimmedName = fullName.trim(); + return trimmedName.isNotEmpty ? trimmedName[0] : '?'; + } } @freezed class ApiSession with _$ApiSession { const ApiSession._(); - const factory ApiSession( - {required String id, - required String user_id, - @Default(1) int? platform, - @Default("") String? fcm_token, - required bool session_active, - String? device_name, - String? device_id, - int? created_at, - String? battery_status, - int? app_version}) = _ApiSession; + const factory ApiSession({required String id, + required String user_id, + @Default(1) int? platform, + @Default("") String? fcm_token, + required bool session_active, + String? device_name, + String? device_id, + int? created_at, + double? battery_pct, + int? app_version}) = _ApiSession; factory ApiSession.fromJson(Map json) => _$ApiSessionFromJson(json); diff --git a/data/lib/api/auth/auth_models.freezed.dart b/data/lib/api/auth/auth_models.freezed.dart index ab486945..6aa34bbe 100644 --- a/data/lib/api/auth/auth_models.freezed.dart +++ b/data/lib/api/auth/auth_models.freezed.dart @@ -399,7 +399,7 @@ mixin _$ApiSession { String? get device_name => throw _privateConstructorUsedError; String? get device_id => throw _privateConstructorUsedError; int? get created_at => throw _privateConstructorUsedError; - String? get battery_status => throw _privateConstructorUsedError; + double? get battery_pct => throw _privateConstructorUsedError; int? get app_version => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @@ -423,7 +423,7 @@ abstract class $ApiSessionCopyWith<$Res> { String? device_name, String? device_id, int? created_at, - String? battery_status, + double? battery_pct, int? app_version}); } @@ -448,7 +448,7 @@ class _$ApiSessionCopyWithImpl<$Res, $Val extends ApiSession> Object? device_name = freezed, Object? device_id = freezed, Object? created_at = freezed, - Object? battery_status = freezed, + Object? battery_pct = freezed, Object? app_version = freezed, }) { return _then(_value.copyWith( @@ -484,10 +484,10 @@ class _$ApiSessionCopyWithImpl<$Res, $Val extends ApiSession> ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable as int?, - battery_status: freezed == battery_status - ? _value.battery_status - : battery_status // ignore: cast_nullable_to_non_nullable - as String?, + battery_pct: freezed == battery_pct + ? _value.battery_pct + : battery_pct // ignore: cast_nullable_to_non_nullable + as double?, app_version: freezed == app_version ? _value.app_version : app_version // ignore: cast_nullable_to_non_nullable @@ -513,7 +513,7 @@ abstract class _$$ApiSessionImplCopyWith<$Res> String? device_name, String? device_id, int? created_at, - String? battery_status, + double? battery_pct, int? app_version}); } @@ -536,7 +536,7 @@ class __$$ApiSessionImplCopyWithImpl<$Res> Object? device_name = freezed, Object? device_id = freezed, Object? created_at = freezed, - Object? battery_status = freezed, + Object? battery_pct = freezed, Object? app_version = freezed, }) { return _then(_$ApiSessionImpl( @@ -572,10 +572,10 @@ class __$$ApiSessionImplCopyWithImpl<$Res> ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable as int?, - battery_status: freezed == battery_status - ? _value.battery_status - : battery_status // ignore: cast_nullable_to_non_nullable - as String?, + battery_pct: freezed == battery_pct + ? _value.battery_pct + : battery_pct // ignore: cast_nullable_to_non_nullable + as double?, app_version: freezed == app_version ? _value.app_version : app_version // ignore: cast_nullable_to_non_nullable @@ -596,7 +596,7 @@ class _$ApiSessionImpl extends _ApiSession { this.device_name, this.device_id, this.created_at, - this.battery_status, + this.battery_pct, this.app_version}) : super._(); @@ -622,13 +622,13 @@ class _$ApiSessionImpl extends _ApiSession { @override final int? created_at; @override - final String? battery_status; + final double? battery_pct; @override final int? app_version; @override String toString() { - return 'ApiSession(id: $id, user_id: $user_id, platform: $platform, fcm_token: $fcm_token, session_active: $session_active, device_name: $device_name, device_id: $device_id, created_at: $created_at, battery_status: $battery_status, app_version: $app_version)'; + return 'ApiSession(id: $id, user_id: $user_id, platform: $platform, fcm_token: $fcm_token, session_active: $session_active, device_name: $device_name, device_id: $device_id, created_at: $created_at, battery_pct: $battery_pct, app_version: $app_version)'; } @override @@ -650,8 +650,8 @@ class _$ApiSessionImpl extends _ApiSession { other.device_id == device_id) && (identical(other.created_at, created_at) || other.created_at == created_at) && - (identical(other.battery_status, battery_status) || - other.battery_status == battery_status) && + (identical(other.battery_pct, battery_pct) || + other.battery_pct == battery_pct) && (identical(other.app_version, app_version) || other.app_version == app_version)); } @@ -668,7 +668,7 @@ class _$ApiSessionImpl extends _ApiSession { device_name, device_id, created_at, - battery_status, + battery_pct, app_version); @JsonKey(ignore: true) @@ -695,7 +695,7 @@ abstract class _ApiSession extends ApiSession { final String? device_name, final String? device_id, final int? created_at, - final String? battery_status, + final double? battery_pct, final int? app_version}) = _$ApiSessionImpl; const _ApiSession._() : super._(); @@ -719,7 +719,7 @@ abstract class _ApiSession extends ApiSession { @override int? get created_at; @override - String? get battery_status; + double? get battery_pct; @override int? get app_version; @override diff --git a/data/lib/api/auth/auth_models.g.dart b/data/lib/api/auth/auth_models.g.dart index 7adc55e7..e9641a33 100644 --- a/data/lib/api/auth/auth_models.g.dart +++ b/data/lib/api/auth/auth_models.g.dart @@ -49,7 +49,7 @@ _$ApiSessionImpl _$$ApiSessionImplFromJson(Map json) => device_name: json['device_name'] as String?, device_id: json['device_id'] as String?, created_at: (json['created_at'] as num?)?.toInt(), - battery_status: json['battery_status'] as String?, + battery_pct: (json['battery_pct'] as num?)?.toDouble(), app_version: (json['app_version'] as num?)?.toInt(), ); @@ -63,7 +63,7 @@ Map _$$ApiSessionImplToJson(_$ApiSessionImpl instance) => 'device_name': instance.device_name, 'device_id': instance.device_id, 'created_at': instance.created_at, - 'battery_status': instance.battery_status, + 'battery_pct': instance.battery_pct, 'app_version': instance.app_version, }; diff --git a/style/lib/button/icon_primary_button.dart b/style/lib/button/icon_primary_button.dart index 3424998a..7ad6a39d 100644 --- a/style/lib/button/icon_primary_button.dart +++ b/style/lib/button/icon_primary_button.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:style/extenstions/context_extenstions.dart'; + +import '../theme/colors.dart'; +import '../theme/theme.dart'; class IconPrimaryButton extends StatelessWidget { final Function() onTap; @@ -9,6 +11,7 @@ class IconPrimaryButton extends StatelessWidget { final Color? iconColor; final double size; final double radius; + final Color? backgroundColor; const IconPrimaryButton({ super.key, @@ -17,19 +20,23 @@ class IconPrimaryButton extends StatelessWidget { this.enabled = true, required this.icon, this.iconColor, + this.backgroundColor, this.size = 40.0, - this.radius = 8, + this.radius = 30, }); @override Widget build(BuildContext context) { + final AppColorScheme colorScheme = appColorSchemeOf(context); + final bg = backgroundColor ?? colorScheme.containerLow; + return GestureDetector( onTap: onTap, child: Container( width: 40, height: 40, decoration: BoxDecoration( - color: context.colorScheme.containerLowOnSurface, + color: bg, borderRadius: BorderRadius.circular(radius), ), padding: const EdgeInsets.all(8), From 246d286dea98a6516ca31560861b981a22a18934 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 12 Jun 2024 21:52:04 +0530 Subject: [PATCH 02/65] Fix user location --- app/lib/ui/flow/home/home_screen.dart | 34 ++- .../ui/flow/home/home_screen_viewmodel.dart | 12 - .../home/home_screen_viewmodel.freezed.dart | 39 +-- .../selected_member_detail_view.dart | 8 +- .../components/space_user_footer.dart | 16 +- app/lib/ui/flow/home/map/map_view.dart | 229 +++++++++++++++++- app/lib/ui/flow/home/map/map_view_model.dart | 143 ++++++++++- app/pubspec.lock | 18 +- app/pubspec.yaml | 3 + data/lib/api/auth/api_user_service.dart | 37 ++- data/lib/api/place/api_place.dart | 13 +- data/lib/api/place/api_place.freezed.dart | 16 +- data/lib/api/place/api_place.g.dart | 6 +- data/lib/service/location_service.dart | 40 +++ data/lib/service/place_service.dart | 28 +++ data/lib/service/space_service.dart | 116 ++++++--- 16 files changed, 600 insertions(+), 158 deletions(-) rename app/lib/ui/flow/home/{ => map}/components/space_user_footer.dart (94%) create mode 100644 data/lib/service/location_service.dart create mode 100644 data/lib/service/place_service.dart diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index c414bd6e..c3f22f0c 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -7,9 +7,9 @@ import 'package:yourspace_flutter/ui/components/app_page.dart'; import 'package:yourspace_flutter/ui/components/error_snakebar.dart'; import 'package:yourspace_flutter/ui/components/resume_detector.dart'; import 'package:yourspace_flutter/ui/flow/home/home_screen_viewmodel.dart'; +import 'package:yourspace_flutter/ui/flow/home/map/map_view_model.dart'; import 'components/home_top_bar.dart'; -import 'components/space_user_footer.dart'; import 'map/map_view.dart'; class HomeScreen extends ConsumerStatefulWidget { @@ -21,6 +21,7 @@ class HomeScreen extends ConsumerStatefulWidget { class _HomeScreenState extends ConsumerState { late HomeViewNotifier notifier; + late MapViewNotifier mapNotifier; @override void initState() { @@ -36,6 +37,9 @@ class _HomeScreenState extends ConsumerState { final state = ref.watch(homeViewStateProvider); _observeNavigation(state); _observeError(); + _observeSelectedSpace(); + + mapNotifier = ref.watch(mapViewStateProvider.notifier); return AppPage( body: ResumeDetector( @@ -52,7 +56,7 @@ class _HomeScreenState extends ConsumerState { padding: context.mediaQueryPadding, child: Stack( children: [ - const MapView(), + MapView(space: state.selectedSpace), HomeTopBar( spaces: state.spaceList, onSpaceItemTap: (name) => notifier.updateSelectedSpace(name), @@ -61,23 +65,6 @@ class _HomeScreenState extends ConsumerState { loading: state.loading, fetchingInviteCode: state.fetchingInviteCode, ), - Positioned( - bottom: 0, - left: 0, - right: 0, - child: SpaceUserFooter( - members: state.selectedSpace?.members, - selectedMember: state.selectedMember, - onAddMemberTap: () => notifier.onAddMemberTap(), - onMemberTap: (member) { - notifier.onSelectMember(member); - }, - onRelocateTap: () {}, - onPlacesTap: () {}, - onDismiss: () => notifier.onDismissMemberDetail(), - onTapTimeline: () {}, - ), - ), ], ), ); @@ -103,4 +90,13 @@ class _HomeScreenState extends ConsumerState { } }); } + + void _observeSelectedSpace() { + ref.listen(homeViewStateProvider.select((state) => state.selectedSpace), + (previous, next) { + if (previous?.space.id != next?.space.id) { + mapNotifier.onSelectedSpaceChange(next?.space.id); + } + }); + } } diff --git a/app/lib/ui/flow/home/home_screen_viewmodel.dart b/app/lib/ui/flow/home/home_screen_viewmodel.dart index a069b8e4..a867494e 100644 --- a/app/lib/ui/flow/home/home_screen_viewmodel.dart +++ b/app/lib/ui/flow/home/home_screen_viewmodel.dart @@ -1,4 +1,3 @@ -import 'package:data/api/auth/auth_models.dart'; import 'package:data/api/space/space_models.dart'; import 'package:data/log/logger.dart'; import 'package:data/service/space_service.dart'; @@ -84,16 +83,6 @@ class HomeViewNotifier extends StateNotifier { currentSpaceId = space.space.id; } } - - void onDismissMemberDetail() { - state = state.copyWith(selectedMember: null); - } - - void onSelectMember(ApiUserInfo member) { - final selectedMember = - (state.selectedMember?.user.id == member.user.id) ? null : member; - state = state.copyWith(selectedMember: selectedMember); - } } @freezed @@ -104,7 +93,6 @@ class HomeViewState with _$HomeViewState { @Default(false) bool loading, @Default(false) bool fetchingInviteCode, SpaceInfo? selectedSpace, - ApiUserInfo? selectedMember, @Default('') String spaceInvitationCode, @Default([]) List spaceList, Object? error, diff --git a/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart b/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart index a7bd013b..6fc49f77 100644 --- a/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart +++ b/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart @@ -21,7 +21,6 @@ mixin _$HomeViewState { bool get loading => throw _privateConstructorUsedError; bool get fetchingInviteCode => throw _privateConstructorUsedError; SpaceInfo? get selectedSpace => throw _privateConstructorUsedError; - ApiUserInfo? get selectedMember => throw _privateConstructorUsedError; String get spaceInvitationCode => throw _privateConstructorUsedError; List get spaceList => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; @@ -43,13 +42,11 @@ abstract class $HomeViewStateCopyWith<$Res> { bool loading, bool fetchingInviteCode, SpaceInfo? selectedSpace, - ApiUserInfo? selectedMember, String spaceInvitationCode, List spaceList, Object? error}); $SpaceInfoCopyWith<$Res>? get selectedSpace; - $ApiUserInfoCopyWith<$Res>? get selectedMember; } /// @nodoc @@ -70,7 +67,6 @@ class _$HomeViewStateCopyWithImpl<$Res, $Val extends HomeViewState> Object? loading = null, Object? fetchingInviteCode = null, Object? selectedSpace = freezed, - Object? selectedMember = freezed, Object? spaceInvitationCode = null, Object? spaceList = null, Object? error = freezed, @@ -96,10 +92,6 @@ class _$HomeViewStateCopyWithImpl<$Res, $Val extends HomeViewState> ? _value.selectedSpace : selectedSpace // ignore: cast_nullable_to_non_nullable as SpaceInfo?, - selectedMember: freezed == selectedMember - ? _value.selectedMember - : selectedMember // ignore: cast_nullable_to_non_nullable - as ApiUserInfo?, spaceInvitationCode: null == spaceInvitationCode ? _value.spaceInvitationCode : spaceInvitationCode // ignore: cast_nullable_to_non_nullable @@ -123,18 +115,6 @@ class _$HomeViewStateCopyWithImpl<$Res, $Val extends HomeViewState> return _then(_value.copyWith(selectedSpace: value) as $Val); }); } - - @override - @pragma('vm:prefer-inline') - $ApiUserInfoCopyWith<$Res>? get selectedMember { - if (_value.selectedMember == null) { - return null; - } - - return $ApiUserInfoCopyWith<$Res>(_value.selectedMember!, (value) { - return _then(_value.copyWith(selectedMember: value) as $Val); - }); - } } /// @nodoc @@ -151,15 +131,12 @@ abstract class _$$HomeViewStateImplCopyWith<$Res> bool loading, bool fetchingInviteCode, SpaceInfo? selectedSpace, - ApiUserInfo? selectedMember, String spaceInvitationCode, List spaceList, Object? error}); @override $SpaceInfoCopyWith<$Res>? get selectedSpace; - @override - $ApiUserInfoCopyWith<$Res>? get selectedMember; } /// @nodoc @@ -178,7 +155,6 @@ class __$$HomeViewStateImplCopyWithImpl<$Res> Object? loading = null, Object? fetchingInviteCode = null, Object? selectedSpace = freezed, - Object? selectedMember = freezed, Object? spaceInvitationCode = null, Object? spaceList = null, Object? error = freezed, @@ -204,10 +180,6 @@ class __$$HomeViewStateImplCopyWithImpl<$Res> ? _value.selectedSpace : selectedSpace // ignore: cast_nullable_to_non_nullable as SpaceInfo?, - selectedMember: freezed == selectedMember - ? _value.selectedMember - : selectedMember // ignore: cast_nullable_to_non_nullable - as ApiUserInfo?, spaceInvitationCode: null == spaceInvitationCode ? _value.spaceInvitationCode : spaceInvitationCode // ignore: cast_nullable_to_non_nullable @@ -230,7 +202,6 @@ class _$HomeViewStateImpl implements _HomeViewState { this.loading = false, this.fetchingInviteCode = false, this.selectedSpace, - this.selectedMember, this.spaceInvitationCode = '', final List spaceList = const [], this.error}) @@ -251,8 +222,6 @@ class _$HomeViewStateImpl implements _HomeViewState { @override final SpaceInfo? selectedSpace; @override - final ApiUserInfo? selectedMember; - @override @JsonKey() final String spaceInvitationCode; final List _spaceList; @@ -269,7 +238,7 @@ class _$HomeViewStateImpl implements _HomeViewState { @override String toString() { - return 'HomeViewState(allowSave: $allowSave, isCreating: $isCreating, loading: $loading, fetchingInviteCode: $fetchingInviteCode, selectedSpace: $selectedSpace, selectedMember: $selectedMember, spaceInvitationCode: $spaceInvitationCode, spaceList: $spaceList, error: $error)'; + return 'HomeViewState(allowSave: $allowSave, isCreating: $isCreating, loading: $loading, fetchingInviteCode: $fetchingInviteCode, selectedSpace: $selectedSpace, spaceInvitationCode: $spaceInvitationCode, spaceList: $spaceList, error: $error)'; } @override @@ -286,8 +255,6 @@ class _$HomeViewStateImpl implements _HomeViewState { other.fetchingInviteCode == fetchingInviteCode) && (identical(other.selectedSpace, selectedSpace) || other.selectedSpace == selectedSpace) && - (identical(other.selectedMember, selectedMember) || - other.selectedMember == selectedMember) && (identical(other.spaceInvitationCode, spaceInvitationCode) || other.spaceInvitationCode == spaceInvitationCode) && const DeepCollectionEquality() @@ -303,7 +270,6 @@ class _$HomeViewStateImpl implements _HomeViewState { loading, fetchingInviteCode, selectedSpace, - selectedMember, spaceInvitationCode, const DeepCollectionEquality().hash(_spaceList), const DeepCollectionEquality().hash(error)); @@ -322,7 +288,6 @@ abstract class _HomeViewState implements HomeViewState { final bool loading, final bool fetchingInviteCode, final SpaceInfo? selectedSpace, - final ApiUserInfo? selectedMember, final String spaceInvitationCode, final List spaceList, final Object? error}) = _$HomeViewStateImpl; @@ -338,8 +303,6 @@ abstract class _HomeViewState implements HomeViewState { @override SpaceInfo? get selectedSpace; @override - ApiUserInfo? get selectedMember; - @override String get spaceInvitationCode; @override List get spaceList; diff --git a/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart b/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart index 0fc405dd..4a7acd7a 100644 --- a/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart +++ b/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart @@ -57,7 +57,6 @@ class _SelectedMemberDetailViewState extends State { ), ), ), - Container( width: context.mediaQuerySize.width, padding: const EdgeInsets.only(top: 24, right: 16), @@ -66,7 +65,6 @@ class _SelectedMemberDetailViewState extends State { children: [_timeLineButtonView()], ), ), - OnTapScale( onTap: () => widget.onDismiss(), child: Container( @@ -211,10 +209,8 @@ class _SelectedMemberDetailViewState extends State { } Future getAddress(ApiLocation? location) async { - // if (location == null) return ''; - // test LatLng(21.231981, 72.8364215) - // LatLng(37.4219999, -122.0840575) - final latLng = LatLng(21.231981, 72.8364215); + if (location == null) return ''; + final latLng = LatLng(location.latitude, location.longitude); final address = await latLng.getAddressFromLocation(); return address; } diff --git a/app/lib/ui/flow/home/components/space_user_footer.dart b/app/lib/ui/flow/home/map/components/space_user_footer.dart similarity index 94% rename from app/lib/ui/flow/home/components/space_user_footer.dart rename to app/lib/ui/flow/home/map/components/space_user_footer.dart index 0b705645..5ce89ab6 100644 --- a/app/lib/ui/flow/home/components/space_user_footer.dart +++ b/app/lib/ui/flow/home/map/components/space_user_footer.dart @@ -7,13 +7,14 @@ import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/text/app_text_dart.dart'; import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; -import '../../../../gen/assets.gen.dart'; -import '../../../components/user_profile_image.dart'; -import '../map/components/selected_member_detail_view.dart'; +import '../../../../../gen/assets.gen.dart'; +import '../../../../components/user_profile_image.dart'; +import 'selected_member_detail_view.dart'; class SpaceUserFooter extends StatelessWidget { final List? members; - final ApiUserInfo? selectedMember; + final ApiUserInfo? selectedUser; + final bool isEnabled; final void Function() onAddMemberTap; final void Function(ApiUserInfo) onMemberTap; final void Function() onRelocateTap; @@ -24,7 +25,8 @@ class SpaceUserFooter extends StatelessWidget { const SpaceUserFooter({ super.key, required this.members, - this.selectedMember, + this.selectedUser, + required this.isEnabled, required this.onAddMemberTap, required this.onMemberTap, required this.onRelocateTap, @@ -41,12 +43,12 @@ class SpaceUserFooter extends StatelessWidget { children: [ _mapControlBtn(context), SelectedMemberDetailView( - userInfo: selectedMember, + userInfo: selectedUser, onDismiss: () => onDismiss(), onTapTimeline: () => onTapTimeline(), ), Visibility( - visible: members != null && members!.isNotEmpty, + visible: isEnabled && members != null && members!.isNotEmpty, child: selectedSpaceMemberView(context: context, members: members)), ], diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index 347fba75..4b3c9116 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -1,30 +1,44 @@ import 'dart:async'; +import 'dart:typed_data'; +import 'dart:ui' as ui; +import 'package:data/api/space/space_models.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:http/http.dart' as http; +import 'package:image/image.dart' as img; +import 'package:style/extenstions/context_extenstions.dart'; + +import 'components/space_user_footer.dart'; +import 'map_view_model.dart'; const defaultCameraZoom = 15; const defaultCameraZoomForSelectedUser = 17; +const markerSize = 100.0; class MapView extends ConsumerStatefulWidget { + final SpaceInfo? space; - const MapView({super.key}); + const MapView({super.key, this.space}); @override ConsumerState createState() => _MapScreenState(); } class _MapScreenState extends ConsumerState { + late MapViewNotifier notifier; final Completer _controller = Completer(); - final _center = const LatLng(0.0, 0.0); - - void _onMapCreated(GoogleMapController controller) { - _controller.complete(controller); - } + final _center = const LatLng(21.2300467, 72.8359667); + List _markers = []; @override Widget build(BuildContext context) { + _observeMarkerChange(); + + notifier = ref.watch(mapViewStateProvider.notifier); + final state = ref.watch(mapViewStateProvider); + return Stack( children: [ Center( @@ -36,9 +50,212 @@ class _MapScreenState extends ConsumerState { myLocationButtonEnabled: false, compassEnabled: false, mapToolbarEnabled: false, + markers: _markers.toSet(), + ), + ), + Positioned( + bottom: 0, + left: 0, + right: 0, + child: SpaceUserFooter( + members: state.userInfo, + selectedUser: state.selectedUser, + isEnabled: !state.loading, + onAddMemberTap: () => + notifier.onAddMemberTap(widget.space!.space.id), + onMemberTap: (member) { + notifier.showMemberDetail(member); + }, + onRelocateTap: () {}, + onPlacesTap: () {}, + onDismiss: () => notifier.onDismissMemberDetail(), + onTapTimeline: () {}, ), ), ], ); } + + void _onMapCreated(GoogleMapController controller) async { + _controller.complete(controller); + } + + void _observeMarkerChange() { + ref.listen(mapViewStateProvider.select((state) => state.markers), + (_, next) { + if (next.isNotEmpty) { + for (final item in next) { + _buildMarkerIcon(item); + } + } else { + setState(() { + _markers = []; + }); + } + }); + } + + void _buildMarkerIcon(UserMarker item) async { + final marker = await _customMarker( + item.isSelected, + item.userName, + item.imageUrl, + item.isSelected + ? context.colorScheme.secondary + : context.colorScheme.surface, + context.colorScheme.primary, + ); + + setState(() { + _markers.add( + Marker( + markerId: MarkerId(item.userId), + position: LatLng(item.latitude, item.longitude), + anchor: const Offset(0.0, 1.0), + icon: marker, + ), + ); + }); + } + + Future _customMarker( + bool isSelected, + String userName, + String? imageUrl, + Color markerBgColor, + Color iconBgColor, + ) async { + if (imageUrl != null && imageUrl.isNotEmpty) { + return await _userImageMarker( + userName, imageUrl, isSelected, markerBgColor, iconBgColor); + } else { + return await _userCharMarker( + isSelected, userName, imageUrl, markerBgColor, iconBgColor); + } + } + + Future _userCharMarker( + bool isSelected, + String userName, + String? imageUrl, + Color markerBgColor, + Color iconBgColor, + ) async { + final pictureRecorder = ui.PictureRecorder(); + final canvas = Canvas(pictureRecorder); + + // Draw background rectangle + canvas.drawRRect( + RRect.fromRectAndCorners( + const Rect.fromLTWH(0.0, 0.0, markerSize, markerSize), + topLeft: const Radius.circular(40), + topRight: const Radius.circular(40), + bottomLeft: const Radius.circular(0), + bottomRight: const Radius.circular(40), + ), + Paint()..color = markerBgColor, + ); + + _drawUserName(canvas, userName, markerSize, iconBgColor); + + final picture = pictureRecorder.endRecording(); + final img = await picture.toImage(markerSize.toInt(), markerSize.toInt()); + final byteData = await img.toByteData(format: ui.ImageByteFormat.png); + final bitmapDescriptor = + BitmapDescriptor.fromBytes(byteData!.buffer.asUint8List()); + + return bitmapDescriptor; + } + + void _drawUserName( + Canvas canvas, String userName, double size, Color bgColor) { + final textPainter = TextPainter(textDirection: TextDirection.ltr); + + canvas.drawCircle( + Offset(size / 2, size / 2), + 40, + Paint()..color = bgColor, + ); + + textPainter.text = TextSpan( + text: userName.isNotEmpty ? userName[0] : '', + style: const TextStyle(fontSize: 50, color: Colors.white), + ); + textPainter.layout(); + textPainter.paint( + canvas, + Offset( + (size - textPainter.width) / 2, + (size - textPainter.height) / 2, + ), + ); + } + + Future _userImageMarker( + String userName, + String imageUrl, + bool isSelected, + Color markerBgColor, + Color iconBgColor, + ) async { + final response = await http.get(Uri.parse(imageUrl)); + if (response.statusCode == 200) { + final bytes = response.bodyBytes; + final image = img.decodeImage(bytes)!; + final resizedImage = img.copyResize(image, width: 80, height: 80); + + // Create a circular image + final circularImage = img.copyCropCircle(resizedImage); + + final byteData = ByteData.view( + Uint8List.fromList(img.encodePng(circularImage)).buffer, + ); + + // Create an Image from the ByteData + final codec = + await ui.instantiateImageCodec(byteData.buffer.asUint8List()); + final frame = await codec.getNextFrame(); + final uiImage = frame.image; + + // Prepare the canvas to draw the rounded rectangle and the image + final recorder = ui.PictureRecorder(); + final canvas = ui.Canvas( + recorder, + Rect.fromPoints( + const Offset(0, 0), const Offset(markerSize, markerSize))); + + // Draw the rounded rectangle + canvas.drawRRect( + RRect.fromRectAndCorners( + const Rect.fromLTWH(0.0, 0.0, markerSize, markerSize), + topLeft: const Radius.circular(40), + topRight: const Radius.circular(40), + bottomLeft: const Radius.circular(0), + bottomRight: const Radius.circular(40), + ), + Paint()..color = markerBgColor, + ); + + // Calculate the position to center the image + final double imageOffset = (markerSize - uiImage.width.toDouble()) / 2; + final Offset offset = Offset(imageOffset, imageOffset); + + // Draw the image on the canvas centered + canvas.drawImage(uiImage, offset, Paint()..color = iconBgColor); + + // End recording and create an image from the canvas + final picture = recorder.endRecording(); + final imgData = + await picture.toImage(markerSize.toInt(), markerSize.toInt()); + final data = await imgData.toByteData(format: ui.ImageByteFormat.png); + + final bitmapDescriptor = + BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); + + return bitmapDescriptor; + } else { + return _userCharMarker( + isSelected, userName, imageUrl, markerBgColor, iconBgColor); + } + } } diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index 5b2712f1..4f375157 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -1,38 +1,159 @@ import 'package:data/api/auth/auth_models.dart'; -import 'package:data/storage/app_preferences.dart'; +import 'package:data/api/place/api_place.dart'; +import 'package:data/log/logger.dart'; +import 'package:data/service/place_service.dart'; +import 'package:data/service/space_service.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; part 'map_view_model.freezed.dart'; final mapViewStateProvider = StateNotifierProvider.autoDispose((ref) { - final notifier = MapViewNotifier( - ref.read(currentUserSessionJsonPod.notifier), + return MapViewNotifier( + ref.read(spaceServiceProvider), + ref.read(placeServiceProvider), ); - return notifier; }); class MapViewNotifier extends StateNotifier { - final StateController _currentSpaceId; + final SpaceService spaceService; + final PlaceService placeService; - MapViewNotifier(this._currentSpaceId) : super(const MapViewState()) { - spaceId(_currentSpaceId.state); + MapViewNotifier(this.spaceService, this.placeService) + : super(const MapViewState()); + + void onSelectedSpaceChange(String? spaceId) { + if (spaceId == null) { + state = state.copyWith(userInfo: [], places: []); + return; + } + state = state.copyWith(markers: []); + listenMemberLocation(spaceId); + listenPlaces(spaceId); + } + + void listenMemberLocation(String spaceId) async { + try { + state = state.copyWith(loading: true, selectedUser: null); + spaceService.getMemberWithLocation(spaceId).listen((userInfo) { + state = state.copyWith(userInfo: userInfo, loading: false); + getUserMarker(userInfo); + }); + } catch (error, stack) { + state = state.copyWith(loading: false, error: error); + logger.e( + 'MapViewNotifier: Error while getting members location', + error: error, + stackTrace: stack, + ); + state = state.copyWith(loading: false); + } + } + + void listenPlaces(String spaceId) async { + try { + placeService.getAllPlacesStream(spaceId).listen((places) { + state = state.copyWith(places: places); + }); + } catch (error, stack) { + logger.e( + 'MapViewNotifier: Error while getting places', + error: error, + stackTrace: stack, + ); + } } - void spaceId(String? spaceId) { - print('XXX space id:${spaceId}'); + void getUserMarker(List userInfo) { + final List markers = []; + for (final info in userInfo) { + if (info.location != null) { + markers.add(UserMarker( + userId: info.user.id, + userName: info.user.fullName, + imageUrl: info.user.profile_image, + latitude: info.location!.latitude, + longitude: info.location!.longitude, + isSelected: false, + )); + } + } + + state = state.copyWith(markers: markers); } - void getSpaceMembersLocation() async { + void onAddMemberTap(String spaceId) async { + try { + state = state.copyWith(fetchingInviteCode: true, spaceInvitationCode: ''); + final code = await spaceService.getInviteCode(spaceId); + state = state.copyWith( + spaceInvitationCode: code ?? '', fetchingInviteCode: false); + } catch (error, stack) { + state = state.copyWith(error: error, fetchingInviteCode: false); + logger.e( + 'MapViewNotifier: Error while getting invitation code', + error: error, + stackTrace: stack, + ); + } + } + void onDismissMemberDetail() { + state = state.copyWith(selectedUser: null); + onShowDetailUpdateUserMarker(null); + + } + + void showMemberDetail(ApiUserInfo member) { + final selectedMember = + (state.selectedUser?.user.id == member.user.id) ? null : member; + state = state.copyWith(selectedUser: selectedMember); + onShowDetailUpdateUserMarker(member.user.id); + } + + void onShowDetailUpdateUserMarker(String? userId) { + final List updatedMarkers; + + if (userId == null) { + updatedMarkers = state.markers + .map((marker) => marker.copyWith(isSelected: false)) + .toList(); + } else { + updatedMarkers = state.markers.map((marker) { + return marker.userId == userId + ? marker.copyWith(isSelected: !marker.isSelected) + : marker.copyWith(isSelected: false); + }).toList(); + } + state = state.copyWith(markers: updatedMarkers); } } @freezed class MapViewState with _$MapViewState { const factory MapViewState({ - ApiUserInfo? selectedMember, + @Default(false) loading, + @Default(false) bool fetchingInviteCode, + @Default([]) List userInfo, + @Default([]) List places, + @Default([]) List markers, + ApiUserInfo? selectedUser, + LatLng? defaultPosition, + @Default('') String spaceInvitationCode, Object? error, }) = _MapViewState; } + +@freezed +class UserMarker with _$UserMarker { + const factory UserMarker({ + required String userId, + required String userName, + required String? imageUrl, + required double latitude, + required double longitude, + required bool isSelected, + }) = _UserMarker; +} diff --git a/app/pubspec.lock b/app/pubspec.lock index 077aa6b8..4b85bb56 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -33,6 +33,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.11.3" + archive: + dependency: transitive + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" args: dependency: transitive description: @@ -773,7 +781,7 @@ packages: source: hosted version: "4.2.0" http: - dependency: transitive + dependency: "direct main" description: name: http sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" @@ -796,6 +804,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: "direct main" + description: + name: image + sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + url: "https://pub.dev" + source: hosted + version: "3.3.0" image_cropper: dependency: "direct main" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 68614af3..ac528ca6 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -54,6 +54,8 @@ dependencies: image_picker: ^1.1.1 image_cropper: ^6.0.0 fluttertoast: ^8.2.6 + http: ^1.2.1 + image: ^3.0.1 # map google_maps_flutter: ^2.2.8 @@ -69,6 +71,7 @@ dependencies: # picker canopas_country_picker: ^0.0.4 + dev_dependencies: flutter_test: sdk: flutter diff --git a/data/lib/api/auth/api_user_service.dart b/data/lib/api/auth/api_user_service.dart index 6367b5f9..93e8a6cd 100644 --- a/data/lib/api/auth/api_user_service.dart +++ b/data/lib/api/auth/api_user_service.dart @@ -1,8 +1,9 @@ import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:firebase_auth/firebase_auth.dart'; import 'package:data/api/network/client.dart'; import 'package:data/service/device_service.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; + import '../../storage/app_preferences.dart'; import 'auth_models.dart'; @@ -12,7 +13,7 @@ final apiUserServiceProvider = StateProvider((ref) => ApiUserService( ref.read(currentUserJsonPod.notifier), ref.read(currentUserSessionJsonPod.notifier), ref.read(currentUserSessionJsonPod.notifier), - ref.read(isOnboardingShownPod.notifier), + ref.read(isOnboardingShownPod.notifier), )); class ApiUserService { @@ -23,8 +24,13 @@ class ApiUserService { final StateController userSessionJsonNotifier; final StateController onBoardNotifier; - ApiUserService(this._db, this._device, this.userJsonNotifier, - this.currentUserSpaceId, this.userSessionJsonNotifier, this.onBoardNotifier); + ApiUserService( + this._db, + this._device, + this.userJsonNotifier, + this.currentUserSpaceId, + this.userSessionJsonNotifier, + this.onBoardNotifier); CollectionReference get _userRef => _db.collection("users").withConverter( @@ -115,8 +121,9 @@ class ApiUserService { } Future deactivateOldSessions(String userId) async { - final querySnapshot = - await _sessionRef(userId).where("session_active", isEqualTo: true).get(); + final querySnapshot = await _sessionRef(userId) + .where("session_active", isEqualTo: true) + .get(); for (var doc in querySnapshot.docs) { await doc.reference.update({"session_active": false}); } @@ -140,14 +147,16 @@ class ApiUserService { }); } - Future updateBatteryPct(String userId, String sessionId, double batteryPct) async { + Future updateBatteryPct( + String userId, String sessionId, double batteryPct) async { await _sessionRef(userId).doc(sessionId).update({ "battery_pct": batteryPct, "updated_at": FieldValue.serverTimestamp(), }); } - Future updateSessionState(String id, String sessionId, int state) async { + Future updateSessionState( + String id, String sessionId, int state) async { await _sessionRef(id).doc(sessionId).update({ "user_state": state, "updated_at": FieldValue.serverTimestamp(), @@ -164,6 +173,18 @@ class ApiUserService { return null; } + Stream getUserSessionStream(String userId) { + return Stream.fromFuture(_sessionRef(userId) + .where("session_active", isEqualTo: true) + .get() + .then((querySnapshot) { + if (querySnapshot.docs.isNotEmpty) { + return querySnapshot.docs.first.data() as ApiSession; + } + return null; + })); + } + Future signOut() async { // locationManager.stopLocationTracking(); userJsonNotifier.state = null; diff --git a/data/lib/api/place/api_place.dart b/data/lib/api/place/api_place.dart index b02402f6..e7b0c785 100644 --- a/data/lib/api/place/api_place.dart +++ b/data/lib/api/place/api_place.dart @@ -16,11 +16,11 @@ class ApiPlace with _$ApiPlace { required double latitude, required double longitude, required double radius, - int? created_at, + DateTime? created_at, }) = _ApiPlace; factory ApiPlace.fromJson(Map data) => - _$ApiPlaceFromJson(data); + _$ApiPlaceFromJson(_convertTimestamps(data)); factory ApiPlace.fromFireStore( DocumentSnapshot> snapshot, @@ -32,6 +32,12 @@ class ApiPlace with _$ApiPlace { Map toFireStore(ApiPlace space) => space.toJson(); } +Map _convertTimestamps(Map json) { + json.update('created_at', (value) => (value as Timestamp).toDate().toString(), + ifAbsent: () => null); + return json; +} + @freezed class ApiPlaceMemberSetting with _$ApiPlaceMemberSetting { const ApiPlaceMemberSetting._(); @@ -54,5 +60,6 @@ class ApiPlaceMemberSetting with _$ApiPlaceMemberSetting { return ApiPlaceMemberSetting.fromJson(data!); } - Map toFireStore(ApiPlaceMemberSetting space) => space.toJson(); + Map toFireStore(ApiPlaceMemberSetting space) => + space.toJson(); } diff --git a/data/lib/api/place/api_place.freezed.dart b/data/lib/api/place/api_place.freezed.dart index afaa305a..b232bdf1 100644 --- a/data/lib/api/place/api_place.freezed.dart +++ b/data/lib/api/place/api_place.freezed.dart @@ -27,7 +27,7 @@ mixin _$ApiPlace { double get latitude => throw _privateConstructorUsedError; double get longitude => throw _privateConstructorUsedError; double get radius => throw _privateConstructorUsedError; - int? get created_at => throw _privateConstructorUsedError; + DateTime? get created_at => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -48,7 +48,7 @@ abstract class $ApiPlaceCopyWith<$Res> { double latitude, double longitude, double radius, - int? created_at}); + DateTime? created_at}); } /// @nodoc @@ -105,7 +105,7 @@ class _$ApiPlaceCopyWithImpl<$Res, $Val extends ApiPlace> created_at: freezed == created_at ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable - as int?, + as DateTime?, ) as $Val); } } @@ -126,7 +126,7 @@ abstract class _$$ApiPlaceImplCopyWith<$Res> double latitude, double longitude, double radius, - int? created_at}); + DateTime? created_at}); } /// @nodoc @@ -181,7 +181,7 @@ class __$$ApiPlaceImplCopyWithImpl<$Res> created_at: freezed == created_at ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable - as int?, + as DateTime?, )); } } @@ -218,7 +218,7 @@ class _$ApiPlaceImpl extends _ApiPlace { @override final double radius; @override - final int? created_at; + final DateTime? created_at; @override String toString() { @@ -273,7 +273,7 @@ abstract class _ApiPlace extends ApiPlace { required final double latitude, required final double longitude, required final double radius, - final int? created_at}) = _$ApiPlaceImpl; + final DateTime? created_at}) = _$ApiPlaceImpl; const _ApiPlace._() : super._(); factory _ApiPlace.fromJson(Map json) = @@ -294,7 +294,7 @@ abstract class _ApiPlace extends ApiPlace { @override double get radius; @override - int? get created_at; + DateTime? get created_at; @override @JsonKey(ignore: true) _$$ApiPlaceImplCopyWith<_$ApiPlaceImpl> get copyWith => diff --git a/data/lib/api/place/api_place.g.dart b/data/lib/api/place/api_place.g.dart index 7a6ec885..eadfeb99 100644 --- a/data/lib/api/place/api_place.g.dart +++ b/data/lib/api/place/api_place.g.dart @@ -15,7 +15,9 @@ _$ApiPlaceImpl _$$ApiPlaceImplFromJson(Map json) => latitude: (json['latitude'] as num).toDouble(), longitude: (json['longitude'] as num).toDouble(), radius: (json['radius'] as num).toDouble(), - created_at: (json['created_at'] as num?)?.toInt(), + created_at: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), ); Map _$$ApiPlaceImplToJson(_$ApiPlaceImpl instance) => @@ -27,7 +29,7 @@ Map _$$ApiPlaceImplToJson(_$ApiPlaceImpl instance) => 'latitude': instance.latitude, 'longitude': instance.longitude, 'radius': instance.radius, - 'created_at': instance.created_at, + 'created_at': instance.created_at?.toIso8601String(), }; _$ApiPlaceMemberSettingImpl _$$ApiPlaceMemberSettingImplFromJson( diff --git a/data/lib/service/location_service.dart b/data/lib/service/location_service.dart new file mode 100644 index 00000000..74956933 --- /dev/null +++ b/data/lib/service/location_service.dart @@ -0,0 +1,40 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../api/auth/auth_models.dart'; +import '../api/location/location.dart'; +import '../api/network/client.dart'; + +final locationServiceProvider = Provider((ref) => LocationService( + ref.read(firestoreProvider), + )); + +class LocationService { + final FirebaseFirestore _db; + + LocationService(this._db); + + CollectionReference get _userRef => + _db.collection("users").withConverter( + fromFirestore: ApiUser.fromFireStore, + toFirestore: (user, options) => user.toJson()); + + CollectionReference _locationRef(String userId) => _userRef + .doc(userId) + .collection("user_locations") + .withConverter( + fromFirestore: ApiLocation.fromFireStore, + toFirestore: (location, _) => location.toJson()); + + Stream?> getCurrentLocationStream(String userId) { + return Stream.fromFuture(_locationRef(userId) + .where("user_id", isEqualTo: userId) + .get() + .then((snapshot) { + if (snapshot.docs.isNotEmpty) { + return snapshot.docs.map((doc) => doc.data() as ApiLocation).toList(); + } + return null; + })); + } +} diff --git a/data/lib/service/place_service.dart b/data/lib/service/place_service.dart new file mode 100644 index 00000000..474ef3c4 --- /dev/null +++ b/data/lib/service/place_service.dart @@ -0,0 +1,28 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:data/api/place/api_place.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../api/network/client.dart'; + +final placeServiceProvider = Provider( + (ref) => PlaceService( + ref.read(firestoreProvider), + ), +); + +class PlaceService { + final FirebaseFirestore _db; + + PlaceService(this._db); + + CollectionReference get _spaceRef => _db.collection('spaces'); + + CollectionReference spacePlacesRef(String spaceId) => + _spaceRef.doc(spaceId).collection('space_places'); + + Stream> getAllPlacesStream(String spaceId) { + return spacePlacesRef(spaceId).snapshots().map((snapshot) => snapshot.docs + .map((doc) => ApiPlace.fromJson(doc.data() as Map)) + .toList()); + } +} diff --git a/data/lib/service/space_service.dart b/data/lib/service/space_service.dart index 1b87b161..66ce2e92 100644 --- a/data/lib/service/space_service.dart +++ b/data/lib/service/space_service.dart @@ -8,14 +8,16 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../api/auth/auth_models.dart'; import '../storage/app_preferences.dart'; +import 'location_service.dart'; final spaceServiceProvider = Provider((ref) => SpaceService( - ref.read(currentUserPod), - ref.read(apiSpaceServiceProvider), - ref.read(apiSpaceInvitationServiceProvider), - ref.read(currentSpaceId.notifier), - ref.read(apiUserServiceProvider), -)); + ref.read(currentUserPod), + ref.read(apiSpaceServiceProvider), + ref.read(apiSpaceInvitationServiceProvider), + ref.read(currentSpaceId.notifier), + ref.read(apiUserServiceProvider), + ref.read(locationServiceProvider), + )); class SpaceService { final ApiUser? currentUser; @@ -23,6 +25,7 @@ class SpaceService { final ApiSpaceInvitationService spaceInvitationService; final StateController _currentSpaceIdController; final ApiUserService userService; + final LocationService locationService; SpaceService( this.currentUser, @@ -30,6 +33,7 @@ class SpaceService { this.spaceInvitationService, this._currentSpaceIdController, this.userService, + this.locationService, ); String? get currentSpaceId => _currentSpaceIdController.state; @@ -59,25 +63,26 @@ class SpaceService { if (spaces.isEmpty) { return spaceInfoList; } - for (final space in spaces) { - if (space == null) continue; - final members = await spaceService.getMembersBySpaceId(space.id); - - final memberInfoList = await Future.wait( - members.map((member) async { - final user = await userService.getUser(member.user_id); - return user != null - ? ApiUserInfo(user: user, isLocationEnabled: member.location_enabled) - : null; - }), - ); - - final nonNullMembers = memberInfoList.whereType().toList(); - - final spaceInfo = SpaceInfo( + for (final space in spaces) { + if (space == null) continue; + final members = await spaceService.getMembersBySpaceId(space.id); + + final memberInfoList = await Future.wait( + members.map((member) async { + final user = await userService.getUser(member.user_id); + return user != null + ? ApiUserInfo( + user: user, isLocationEnabled: member.location_enabled) + : null; + }), + ); + + final nonNullMembers = memberInfoList.whereType().toList(); + + final spaceInfo = SpaceInfo( space: space, members: nonNullMembers, - ); + ); spaceInfoList.add(spaceInfo); } return spaceInfoList; @@ -91,11 +96,12 @@ class SpaceService { space: currentSpace, members: members .map((member) async { - final user = await userService.getUser(member.user_id); - return user != null - ? ApiUserInfo(user: user, isLocationEnabled: member.location_enabled) - : null; - }) + final user = await userService.getUser(member.user_id); + return user != null + ? ApiUserInfo( + user: user, isLocationEnabled: member.location_enabled) + : null; + }) .whereType() .toList(), ); @@ -108,7 +114,9 @@ class SpaceService { final members = await spaceService.getMembersBySpaceId(space.id); final memberInfo = await Future.wait(members.map((member) async { final user = await userService.getUser(member.user_id); - return user != null ? ApiUserInfo(user: user, isLocationEnabled: member.location_enabled) : null; + return user != null + ? ApiUserInfo(user: user, isLocationEnabled: member.location_enabled) + : null; }).toList()); return SpaceInfo( @@ -141,8 +149,7 @@ class SpaceService { return spaceService.getSpace(spaceId); } - Future> getMemberBySpaceId( - String spaceId) async { + Future> getMemberBySpaceId(String spaceId) async { return spaceService.getMembersBySpaceId(spaceId); } @@ -162,8 +169,10 @@ class SpaceService { Future deleteUserSpaces() async { final userId = currentUser?.id ?? ''; final allSpace = await getUserSpaces(userId); - final ownSpace = allSpace.where((space) => space?.admin_id == userId).toList(); - final joinedSpace = allSpace.where((space) => space?.admin_id != userId).toList(); + final ownSpace = + allSpace.where((space) => space?.admin_id == userId).toList(); + final joinedSpace = + allSpace.where((space) => space?.admin_id != userId).toList(); for (final space in ownSpace) { await deleteSpace(space!.id); @@ -180,8 +189,10 @@ class SpaceService { await spaceService.deleteSpace(spaceId); final userId = currentUser?.id ?? ''; final userSpaces = await getUserSpaces(userId); - userSpaces.sort((a, b) => (a?.created_at ?? 0).compareTo(b?.created_at ?? 0)); - final currentSpaceId = userSpaces.isNotEmpty ? userSpaces.firstOrNull?.id ?? '' : ''; + userSpaces + .sort((a, b) => (a?.created_at ?? 0).compareTo(b?.created_at ?? 0)); + final currentSpaceId = + userSpaces.isNotEmpty ? userSpaces.firstOrNull?.id ?? '' : ''; this.currentSpaceId = currentSpaceId; } @@ -189,12 +200,43 @@ class SpaceService { final userId = currentUser?.id ?? ''; await spaceService.removeUserFromSpace(spaceId, userId); final userSpaces = await getUserSpaces(userId); - userSpaces.sort((a, b) => (a?.created_at ?? 0).compareTo(b?.created_at ?? 0)); - final currentSpaceId = userSpaces.isNotEmpty ? userSpaces.firstOrNull?.id ?? '' : ''; + userSpaces + .sort((a, b) => (a?.created_at ?? 0).compareTo(b?.created_at ?? 0)); + final currentSpaceId = + userSpaces.isNotEmpty ? userSpaces.firstOrNull?.id ?? '' : ''; this.currentSpaceId = currentSpaceId; } Future updateSpace(ApiSpace newSpace) async { await spaceService.updateSpace(newSpace); } + + Stream> getMemberWithLocation(String spaceId) { + return Stream.fromFuture(Future(() async { + List userInfo = []; + final members = await spaceService.getMembersBySpaceId(spaceId); + + if (members.isEmpty) return []; + + for (final member in members) { + final userStream = userService.getUserStream(member.user_id); + final sessionStream = userService.getUserSessionStream(member.user_id); + final user = await userStream.first; + final locationStream = + locationService.getCurrentLocationStream(user!.id); + + final session = await sessionStream.first; + final location = await locationStream.first; + + userInfo.add(ApiUserInfo( + user: user, + location: location?.firstOrNull, + isLocationEnabled: member.location_enabled, + session: session, + )); + } + + return userInfo; + })); + } } From 3101c96a5070e3bf42df01579fa5eac71df8ebd3 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 12 Jun 2024 21:52:12 +0530 Subject: [PATCH 03/65] Fix user location --- .../flow/home/map/map_view_model.freezed.dart | 572 ++++++++++++++++++ 1 file changed, 572 insertions(+) create mode 100644 app/lib/ui/flow/home/map/map_view_model.freezed.dart diff --git a/app/lib/ui/flow/home/map/map_view_model.freezed.dart b/app/lib/ui/flow/home/map/map_view_model.freezed.dart new file mode 100644 index 00000000..59fbfb61 --- /dev/null +++ b/app/lib/ui/flow/home/map/map_view_model.freezed.dart @@ -0,0 +1,572 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'map_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$MapViewState { + dynamic get loading => throw _privateConstructorUsedError; + bool get fetchingInviteCode => throw _privateConstructorUsedError; + List get userInfo => throw _privateConstructorUsedError; + List get places => throw _privateConstructorUsedError; + List get markers => throw _privateConstructorUsedError; + ApiUserInfo? get selectedUser => throw _privateConstructorUsedError; + LatLng? get defaultPosition => throw _privateConstructorUsedError; + String get spaceInvitationCode => throw _privateConstructorUsedError; + Object? get error => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $MapViewStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MapViewStateCopyWith<$Res> { + factory $MapViewStateCopyWith( + MapViewState value, $Res Function(MapViewState) then) = + _$MapViewStateCopyWithImpl<$Res, MapViewState>; + @useResult + $Res call( + {dynamic loading, + bool fetchingInviteCode, + List userInfo, + List places, + List markers, + ApiUserInfo? selectedUser, + LatLng? defaultPosition, + String spaceInvitationCode, + Object? error}); + + $ApiUserInfoCopyWith<$Res>? get selectedUser; +} + +/// @nodoc +class _$MapViewStateCopyWithImpl<$Res, $Val extends MapViewState> + implements $MapViewStateCopyWith<$Res> { + _$MapViewStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = freezed, + Object? fetchingInviteCode = null, + Object? userInfo = null, + Object? places = null, + Object? markers = null, + Object? selectedUser = freezed, + Object? defaultPosition = freezed, + Object? spaceInvitationCode = null, + Object? error = freezed, + }) { + return _then(_value.copyWith( + loading: freezed == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as dynamic, + fetchingInviteCode: null == fetchingInviteCode + ? _value.fetchingInviteCode + : fetchingInviteCode // ignore: cast_nullable_to_non_nullable + as bool, + userInfo: null == userInfo + ? _value.userInfo + : userInfo // ignore: cast_nullable_to_non_nullable + as List, + places: null == places + ? _value.places + : places // ignore: cast_nullable_to_non_nullable + as List, + markers: null == markers + ? _value.markers + : markers // ignore: cast_nullable_to_non_nullable + as List, + selectedUser: freezed == selectedUser + ? _value.selectedUser + : selectedUser // ignore: cast_nullable_to_non_nullable + as ApiUserInfo?, + defaultPosition: freezed == defaultPosition + ? _value.defaultPosition + : defaultPosition // ignore: cast_nullable_to_non_nullable + as LatLng?, + spaceInvitationCode: null == spaceInvitationCode + ? _value.spaceInvitationCode + : spaceInvitationCode // ignore: cast_nullable_to_non_nullable + as String, + error: freezed == error ? _value.error : error, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ApiUserInfoCopyWith<$Res>? get selectedUser { + if (_value.selectedUser == null) { + return null; + } + + return $ApiUserInfoCopyWith<$Res>(_value.selectedUser!, (value) { + return _then(_value.copyWith(selectedUser: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$MapViewStateImplCopyWith<$Res> + implements $MapViewStateCopyWith<$Res> { + factory _$$MapViewStateImplCopyWith( + _$MapViewStateImpl value, $Res Function(_$MapViewStateImpl) then) = + __$$MapViewStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {dynamic loading, + bool fetchingInviteCode, + List userInfo, + List places, + List markers, + ApiUserInfo? selectedUser, + LatLng? defaultPosition, + String spaceInvitationCode, + Object? error}); + + @override + $ApiUserInfoCopyWith<$Res>? get selectedUser; +} + +/// @nodoc +class __$$MapViewStateImplCopyWithImpl<$Res> + extends _$MapViewStateCopyWithImpl<$Res, _$MapViewStateImpl> + implements _$$MapViewStateImplCopyWith<$Res> { + __$$MapViewStateImplCopyWithImpl( + _$MapViewStateImpl _value, $Res Function(_$MapViewStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = freezed, + Object? fetchingInviteCode = null, + Object? userInfo = null, + Object? places = null, + Object? markers = null, + Object? selectedUser = freezed, + Object? defaultPosition = freezed, + Object? spaceInvitationCode = null, + Object? error = freezed, + }) { + return _then(_$MapViewStateImpl( + loading: freezed == loading ? _value.loading! : loading, + fetchingInviteCode: null == fetchingInviteCode + ? _value.fetchingInviteCode + : fetchingInviteCode // ignore: cast_nullable_to_non_nullable + as bool, + userInfo: null == userInfo + ? _value._userInfo + : userInfo // ignore: cast_nullable_to_non_nullable + as List, + places: null == places + ? _value._places + : places // ignore: cast_nullable_to_non_nullable + as List, + markers: null == markers + ? _value._markers + : markers // ignore: cast_nullable_to_non_nullable + as List, + selectedUser: freezed == selectedUser + ? _value.selectedUser + : selectedUser // ignore: cast_nullable_to_non_nullable + as ApiUserInfo?, + defaultPosition: freezed == defaultPosition + ? _value.defaultPosition + : defaultPosition // ignore: cast_nullable_to_non_nullable + as LatLng?, + spaceInvitationCode: null == spaceInvitationCode + ? _value.spaceInvitationCode + : spaceInvitationCode // ignore: cast_nullable_to_non_nullable + as String, + error: freezed == error ? _value.error : error, + )); + } +} + +/// @nodoc + +class _$MapViewStateImpl implements _MapViewState { + const _$MapViewStateImpl( + {this.loading = false, + this.fetchingInviteCode = false, + final List userInfo = const [], + final List places = const [], + final List markers = const [], + this.selectedUser, + this.defaultPosition, + this.spaceInvitationCode = '', + this.error}) + : _userInfo = userInfo, + _places = places, + _markers = markers; + + @override + @JsonKey() + final dynamic loading; + @override + @JsonKey() + final bool fetchingInviteCode; + final List _userInfo; + @override + @JsonKey() + List get userInfo { + if (_userInfo is EqualUnmodifiableListView) return _userInfo; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_userInfo); + } + + final List _places; + @override + @JsonKey() + List get places { + if (_places is EqualUnmodifiableListView) return _places; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_places); + } + + final List _markers; + @override + @JsonKey() + List get markers { + if (_markers is EqualUnmodifiableListView) return _markers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_markers); + } + + @override + final ApiUserInfo? selectedUser; + @override + final LatLng? defaultPosition; + @override + @JsonKey() + final String spaceInvitationCode; + @override + final Object? error; + + @override + String toString() { + return 'MapViewState(loading: $loading, fetchingInviteCode: $fetchingInviteCode, userInfo: $userInfo, places: $places, markers: $markers, selectedUser: $selectedUser, defaultPosition: $defaultPosition, spaceInvitationCode: $spaceInvitationCode, error: $error)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MapViewStateImpl && + const DeepCollectionEquality().equals(other.loading, loading) && + (identical(other.fetchingInviteCode, fetchingInviteCode) || + other.fetchingInviteCode == fetchingInviteCode) && + const DeepCollectionEquality().equals(other._userInfo, _userInfo) && + const DeepCollectionEquality().equals(other._places, _places) && + const DeepCollectionEquality().equals(other._markers, _markers) && + (identical(other.selectedUser, selectedUser) || + other.selectedUser == selectedUser) && + (identical(other.defaultPosition, defaultPosition) || + other.defaultPosition == defaultPosition) && + (identical(other.spaceInvitationCode, spaceInvitationCode) || + other.spaceInvitationCode == spaceInvitationCode) && + const DeepCollectionEquality().equals(other.error, error)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(loading), + fetchingInviteCode, + const DeepCollectionEquality().hash(_userInfo), + const DeepCollectionEquality().hash(_places), + const DeepCollectionEquality().hash(_markers), + selectedUser, + defaultPosition, + spaceInvitationCode, + const DeepCollectionEquality().hash(error)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MapViewStateImplCopyWith<_$MapViewStateImpl> get copyWith => + __$$MapViewStateImplCopyWithImpl<_$MapViewStateImpl>(this, _$identity); +} + +abstract class _MapViewState implements MapViewState { + const factory _MapViewState( + {final dynamic loading, + final bool fetchingInviteCode, + final List userInfo, + final List places, + final List markers, + final ApiUserInfo? selectedUser, + final LatLng? defaultPosition, + final String spaceInvitationCode, + final Object? error}) = _$MapViewStateImpl; + + @override + dynamic get loading; + @override + bool get fetchingInviteCode; + @override + List get userInfo; + @override + List get places; + @override + List get markers; + @override + ApiUserInfo? get selectedUser; + @override + LatLng? get defaultPosition; + @override + String get spaceInvitationCode; + @override + Object? get error; + @override + @JsonKey(ignore: true) + _$$MapViewStateImplCopyWith<_$MapViewStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$UserMarker { + String get userId => throw _privateConstructorUsedError; + String get userName => throw _privateConstructorUsedError; + String? get imageUrl => throw _privateConstructorUsedError; + double get latitude => throw _privateConstructorUsedError; + double get longitude => throw _privateConstructorUsedError; + bool get isSelected => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $UserMarkerCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $UserMarkerCopyWith<$Res> { + factory $UserMarkerCopyWith( + UserMarker value, $Res Function(UserMarker) then) = + _$UserMarkerCopyWithImpl<$Res, UserMarker>; + @useResult + $Res call( + {String userId, + String userName, + String? imageUrl, + double latitude, + double longitude, + bool isSelected}); +} + +/// @nodoc +class _$UserMarkerCopyWithImpl<$Res, $Val extends UserMarker> + implements $UserMarkerCopyWith<$Res> { + _$UserMarkerCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? userId = null, + Object? userName = null, + Object? imageUrl = freezed, + Object? latitude = null, + Object? longitude = null, + Object? isSelected = null, + }) { + return _then(_value.copyWith( + userId: null == userId + ? _value.userId + : userId // ignore: cast_nullable_to_non_nullable + as String, + userName: null == userName + ? _value.userName + : userName // ignore: cast_nullable_to_non_nullable + as String, + imageUrl: freezed == imageUrl + ? _value.imageUrl + : imageUrl // ignore: cast_nullable_to_non_nullable + as String?, + latitude: null == latitude + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as double, + longitude: null == longitude + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as double, + isSelected: null == isSelected + ? _value.isSelected + : isSelected // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$UserMarkerImplCopyWith<$Res> + implements $UserMarkerCopyWith<$Res> { + factory _$$UserMarkerImplCopyWith( + _$UserMarkerImpl value, $Res Function(_$UserMarkerImpl) then) = + __$$UserMarkerImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String userId, + String userName, + String? imageUrl, + double latitude, + double longitude, + bool isSelected}); +} + +/// @nodoc +class __$$UserMarkerImplCopyWithImpl<$Res> + extends _$UserMarkerCopyWithImpl<$Res, _$UserMarkerImpl> + implements _$$UserMarkerImplCopyWith<$Res> { + __$$UserMarkerImplCopyWithImpl( + _$UserMarkerImpl _value, $Res Function(_$UserMarkerImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? userId = null, + Object? userName = null, + Object? imageUrl = freezed, + Object? latitude = null, + Object? longitude = null, + Object? isSelected = null, + }) { + return _then(_$UserMarkerImpl( + userId: null == userId + ? _value.userId + : userId // ignore: cast_nullable_to_non_nullable + as String, + userName: null == userName + ? _value.userName + : userName // ignore: cast_nullable_to_non_nullable + as String, + imageUrl: freezed == imageUrl + ? _value.imageUrl + : imageUrl // ignore: cast_nullable_to_non_nullable + as String?, + latitude: null == latitude + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as double, + longitude: null == longitude + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as double, + isSelected: null == isSelected + ? _value.isSelected + : isSelected // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc + +class _$UserMarkerImpl implements _UserMarker { + const _$UserMarkerImpl( + {required this.userId, + required this.userName, + required this.imageUrl, + required this.latitude, + required this.longitude, + required this.isSelected}); + + @override + final String userId; + @override + final String userName; + @override + final String? imageUrl; + @override + final double latitude; + @override + final double longitude; + @override + final bool isSelected; + + @override + String toString() { + return 'UserMarker(userId: $userId, userName: $userName, imageUrl: $imageUrl, latitude: $latitude, longitude: $longitude, isSelected: $isSelected)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$UserMarkerImpl && + (identical(other.userId, userId) || other.userId == userId) && + (identical(other.userName, userName) || + other.userName == userName) && + (identical(other.imageUrl, imageUrl) || + other.imageUrl == imageUrl) && + (identical(other.latitude, latitude) || + other.latitude == latitude) && + (identical(other.longitude, longitude) || + other.longitude == longitude) && + (identical(other.isSelected, isSelected) || + other.isSelected == isSelected)); + } + + @override + int get hashCode => Object.hash( + runtimeType, userId, userName, imageUrl, latitude, longitude, isSelected); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$UserMarkerImplCopyWith<_$UserMarkerImpl> get copyWith => + __$$UserMarkerImplCopyWithImpl<_$UserMarkerImpl>(this, _$identity); +} + +abstract class _UserMarker implements UserMarker { + const factory _UserMarker( + {required final String userId, + required final String userName, + required final String? imageUrl, + required final double latitude, + required final double longitude, + required final bool isSelected}) = _$UserMarkerImpl; + + @override + String get userId; + @override + String get userName; + @override + String? get imageUrl; + @override + double get latitude; + @override + double get longitude; + @override + bool get isSelected; + @override + @JsonKey(ignore: true) + _$$UserMarkerImplCopyWith<_$UserMarkerImpl> get copyWith => + throw _privateConstructorUsedError; +} From 86185f7209a7fd03e597c6f4a7af35c8b4c110d2 Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 14 Jun 2024 15:37:25 +0530 Subject: [PATCH 04/65] Fix place and marker --- app/assets/images/ic_place_marker_icon.png | Bin 0 -> 2408 bytes app/ios/Runner/AppDelegate.swift | 6 + app/ios/Runner/Info.plist | 2 + .../extenstions/lat_lng_extenstion.dart | 16 +- app/lib/gen/assets.gen.dart | 5 + app/lib/ui/flow/home/home_screen.dart | 2 +- .../selected_member_detail_view.dart | 43 +-- .../map/components/space_user_footer.dart | 31 +- app/lib/ui/flow/home/map/map_view.dart | 311 +++++++++++++----- app/lib/ui/flow/home/map/map_view_model.dart | 65 +++- .../flow/home/map/map_view_model.freezed.dart | 16 +- app/pubspec.lock | 2 +- app/pubspec.yaml | 1 + 13 files changed, 357 insertions(+), 143 deletions(-) create mode 100644 app/assets/images/ic_place_marker_icon.png diff --git a/app/assets/images/ic_place_marker_icon.png b/app/assets/images/ic_place_marker_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..88740138e7dbc768b6bbe60e78fe9938ee81fc4d GIT binary patch literal 2408 zcmV-u377VXP)nS!K~#7F?VU?( zR8<(qzYf)@F(fg6s# zuu0%@t8goGn`XhwBn%M(D+}GtZ6|qx7APBF(PeHIxm{zyT{0YF1#S?vNM=&zRw9GN zHcnvWen+?sQFfLZg%Y=MiEcaiZ8R&_ow~p*tiy+Mlz(9xDRDcTb~3h%QiR3b%ZHn^^uz@t+z_7+Qi`Nv!Asa` zTj6pWOv9QJx8NmiwXJZ-v*vx2Fo{`k%_~&E9VPxx2u?x)NLR5(BkVOZV5)e7o7|i0LZahg=+$cEY#pRt8Be7Yqs@jyu5(gt}$>S6Q zu?TF%O@vrP?pk0gZlZK8a#sSYcrihiBpGIrFH%Gz3#__AC}2n$vy}+?$H=ZL6oE)t zv=SHDvK2RZaE>R`IoC$pf>nhImg|ruO<=);x)rY|7L4+vLzc8b0ZDr#N=slhaA0f8 z*|AS|fFiVuwn>#Sz(sEgThi3AV4GB#0W>%l_RXOLRD`;!~3R=zI=YVH2>Sh9$$Xi)2lIydN>DVtb z^`j2EHm{}q@2`_CbcqEX4L-3*U{$r6C4oGc`-i^0RH2{lJfvbJya63pf6t;qR~2f2TlD-5Lo#(P+Vly+snl@vAd*j9U_X&6W&n7RI7v zYe8U%?m05hPXc8U7F_4 zd_sa)&{CuY51+lZ(5Fp~fB20Au~4L{3#^J8BF22r|L)R*YWmiMe)V}duDalt zE`19YQmhQ{RZNU=$&ALEZU_t#8l( z*PBsy2Dcto>CE+ek+NfC?;oyPMFPNf%haQmqRf%uAaj2E*k!GsS>3msCO+TRvh0Z8 ziG)qpE8IOWRKIWp&<7VS!g_B#(%*!pow%TW0qohPEfz+pgs@SJz)?nr!VDNdWVmo0 zF#IS42Lg-e9wBb(Fs30I;&YOJONP`fcmoLl@luENE5l#6e)1LiZ>fr@YW0e-V3SU& z?!}fNa$K}7Q}@Hi?AwpTxLjTGE3i&dc6#a_+as*!gN-yc+RllzAP~WeM3MKWKmpq<~ zd0bJFw>5?3B!%Zl2y6*3m=Q-#1T2?71jU7H=sim)S822mF{ zzVtE$vYdo2a02|is2B{8_~4ITkvvHnHCI?&5oszRU@&=GO_ED$}+VI%_V_g!3M*!13Yi|;jQTPRUts+)GecOvszBc)kX0YqzCrqa9c6qGZNWass^g5u zaQ$NjRL#1iu4!}_++a|cZbO$jT6nDv^V9*2YNT

hmA3Wr*~ z(CNllHWr&tOX~%lCcfKPY(8y0ZCim=%3UUlsg&B?w-DId%gQC5+smq7U|qF&oD6fD z_l_3qV-qf;Xq#9C(OF%HV4mCkh6Di(2E)ENw7}L?8^hr+uGuHFi}qnxjgr`2vSb0` z?mnF#h$1kuX~bi(Q~rhGl9x4Wg-Pud{^|pUN$7GHp}6D?1#0I&+7|4?mJADqCENaS zvV`jIwj%N#9sGfqM{Nfrl4mrkxS*>|Soni4k`*~gM%6ivOk@`wgx&QBAI^~_P9ScH zx+E5XffYGcVi6a_CNN-;cakTvO}wIkgsN+|93)nOff{{6cI}Ww2bbHhN?v0lc7cHv zSsREt+)cLJibS?DRDUR@aGoSfCvc7ilMojqV!=V!no&DFNH#7vf_RI8gAi3<#@ z%YKG3by>g&ODem~;vZ21)EI7D%45p--@oE>F_?z9AQcM^qOAE4x81a~C{s#S8zgms zebgd1^qC#XH)Zl-ZJCxLsDNRaOf7%R*1U_@0&1SnH*4~ltQjP1W-huF>g0@&tQd{t z3FXCc(_FD}0{hgwWUNS@&_yznGCdX6$ligm0tX3*J*19V6-^)_%8Evd8bpM^jVL#c z-BobJ)FFqG!6i@7GPh}onXpKK8>x9SJs~ti?^DM@pgB!`tV&OdF0N|x Bool { + GMSServices.provideAPIKey(getMapKey()) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + + func getMapKey() -> String { + let mapApiKey = Bundle.main.object(forInfoDictionaryKey: "MapApiKey") as? String + return mapApiKey ?? "" + } } diff --git a/app/ios/Runner/Info.plist b/app/ios/Runner/Info.plist index a31e8613..d39c96b3 100644 --- a/app/ios/Runner/Info.plist +++ b/app/ios/Runner/Info.plist @@ -58,5 +58,7 @@ App requires permission to access photos NSCameraUsageDescription App requires permission to access camera + MapApiKey + AIzaSyDbaJSVGU4Jkhd_V_e9esorzh_8yykh160 diff --git a/app/lib/domain/extenstions/lat_lng_extenstion.dart b/app/lib/domain/extenstions/lat_lng_extenstion.dart index 69e5a48d..a8b16779 100644 --- a/app/lib/domain/extenstions/lat_lng_extenstion.dart +++ b/app/lib/domain/extenstions/lat_lng_extenstion.dart @@ -3,8 +3,18 @@ import 'package:geocoding/geocoding.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; extension LatLngExtensions on LatLng { + static String? _cachedAddress; + static LatLng? _cachedLatLng; + Future getAddressFromLocation() async { - String? address = ''; + if (_cachedLatLng != null && + _cachedLatLng!.latitude == latitude && + _cachedLatLng!.longitude == longitude && + _cachedAddress != null) { + return _cachedAddress!; + } + + String address = ''; try { final placeMarks = await placemarkFromCoordinates(latitude, longitude); if (placeMarks.isNotEmpty) { @@ -25,6 +35,10 @@ extension LatLngExtensions on LatLng { address += ', ${placeMarks.reversed.last.postalCode ?? ''}'; address += ', ${placeMarks.reversed.last.country ?? ''}'; } + + _cachedLatLng = LatLng(latitude, longitude); + _cachedAddress = address; + return address; } catch (e) { logger.e('GetAddress: Error while getting address', error: e); diff --git a/app/lib/gen/assets.gen.dart b/app/lib/gen/assets.gen.dart index f65bc03f..994d2d88 100644 --- a/app/lib/gen/assets.gen.dart +++ b/app/lib/gen/assets.gen.dart @@ -58,6 +58,10 @@ class $AssetsImagesGen { /// File path: assets/images/ic_message.svg String get icMessage => 'assets/images/ic_message.svg'; + /// File path: assets/images/ic_place_marker_icon.png + AssetGenImage get icPlaceMarkerIcon => + const AssetGenImage('assets/images/ic_place_marker_icon.png'); + /// File path: assets/images/ic_privacy_policy.svg String get icPrivacyPolicy => 'assets/images/ic_privacy_policy.svg'; @@ -107,6 +111,7 @@ class $AssetsImagesGen { icGoogleLogo, icLocation, icMessage, + icPlaceMarkerIcon, icPrivacyPolicy, icRelocateIcon, icRemove, diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index c3f22f0c..64a3fb79 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -95,7 +95,7 @@ class _HomeScreenState extends ConsumerState { ref.listen(homeViewStateProvider.select((state) => state.selectedSpace), (previous, next) { if (previous?.space.id != next?.space.id) { - mapNotifier.onSelectedSpaceChange(next?.space.id); + mapNotifier.loadData(next?.space.id); } }); } diff --git a/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart b/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart index 4a7acd7a..7538ae8b 100644 --- a/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart +++ b/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart @@ -30,6 +30,8 @@ class SelectedMemberDetailView extends StatefulWidget { } class _SelectedMemberDetailViewState extends State { + String? address = ''; + @override Widget build(BuildContext context) { final userInfo = widget.userInfo; @@ -123,22 +125,14 @@ class _SelectedMemberDetailViewState extends State { } Widget _userAddressView(ApiLocation? location) { - return FutureBuilder( - future: getAddress(location), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - final address = snapshot.data ?? ''; - return Text( - address, - style: AppTextStyle.body2 - .copyWith(color: context.colorScheme.textPrimary), - overflow: TextOverflow.ellipsis, - maxLines: 2, - ); - } else { - return const SizedBox(height: 16); - } - }, + getAddress(location); + return Text( + address ?? '', + style: AppTextStyle.body2.copyWith( + color: context.colorScheme.textPrimary, + ), + overflow: TextOverflow.ellipsis, + maxLines: 2, ); } @@ -208,10 +202,17 @@ class _SelectedMemberDetailViewState extends State { } } - Future getAddress(ApiLocation? location) async { - if (location == null) return ''; - final latLng = LatLng(location.latitude, location.longitude); - final address = await latLng.getAddressFromLocation(); - return address; + void getAddress(ApiLocation? location) async { + if (location != null) { + final latLng = LatLng(location.latitude, location.longitude); + final address = await latLng.getAddressFromLocation(); + setState(() { + this.address = address; + }); + } else { + setState(() { + address = ''; + }); + } } } diff --git a/app/lib/ui/flow/home/map/components/space_user_footer.dart b/app/lib/ui/flow/home/map/components/space_user_footer.dart index 5ce89ab6..43a5b03f 100644 --- a/app/lib/ui/flow/home/map/components/space_user_footer.dart +++ b/app/lib/ui/flow/home/map/components/space_user_footer.dart @@ -11,7 +11,7 @@ import '../../../../../gen/assets.gen.dart'; import '../../../../components/user_profile_image.dart'; import 'selected_member_detail_view.dart'; -class SpaceUserFooter extends StatelessWidget { +class SpaceUserFooter extends StatefulWidget { final List? members; final ApiUserInfo? selectedUser; final bool isEnabled; @@ -35,6 +35,11 @@ class SpaceUserFooter extends StatelessWidget { required this.onTapTimeline, }); + @override + State createState() => _SpaceUserFooterState(); +} + +class _SpaceUserFooterState extends State { @override Widget build(BuildContext context) { return Padding( @@ -43,14 +48,18 @@ class SpaceUserFooter extends StatelessWidget { children: [ _mapControlBtn(context), SelectedMemberDetailView( - userInfo: selectedUser, - onDismiss: () => onDismiss(), - onTapTimeline: () => onTapTimeline(), + userInfo: widget.selectedUser, + onDismiss: widget.onDismiss, + onTapTimeline: widget.onTapTimeline, ), Visibility( - visible: isEnabled && members != null && members!.isNotEmpty, - child: - selectedSpaceMemberView(context: context, members: members)), + visible: widget.isEnabled && + widget.members != null && + widget.members!.isNotEmpty, + child: selectedSpaceMemberView( + context: context, + members: widget.members, + )), ], ), ); @@ -69,7 +78,7 @@ class SpaceUserFooter extends StatelessWidget { foreground: context.colorScheme.primary, background: context.colorScheme.surface, visibility: true, - onTap: () => onRelocateTap, + onTap: widget.onRelocateTap, ), const SizedBox(height: 8), _iconButton( @@ -79,7 +88,7 @@ class SpaceUserFooter extends StatelessWidget { foreground: context.colorScheme.onPrimary, background: context.colorScheme.primary, visibility: true, - onTap: () => onPlacesTap, + onTap: widget.onPlacesTap, ) ], ), @@ -133,7 +142,7 @@ class SpaceUserFooter extends StatelessWidget { Widget addMemberView(BuildContext context) { return OnTapScale( - onTap: () => onAddMemberTap(), + onTap: widget.onAddMemberTap, child: Padding( padding: const EdgeInsets.only(right: 6), child: Column( @@ -177,7 +186,7 @@ class SpaceUserFooter extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 6), child: OnTapScale( onTap: () { - onMemberTap(userInfo); + widget.onMemberTap(userInfo); }, child: SizedBox( width: 40, diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index 4b3c9116..8830509c 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -1,21 +1,25 @@ import 'dart:async'; -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:data/api/space/space_models.dart'; +import 'package:data/log/logger.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:http/http.dart' as http; import 'package:image/image.dart' as img; import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/text/app_text_dart.dart'; +import '../../../app_route.dart'; import 'components/space_user_footer.dart'; import 'map_view_model.dart'; -const defaultCameraZoom = 15; -const defaultCameraZoomForSelectedUser = 17; +const defaultCameraZoom = 15.0; +const defaultCameraZoomForSelectedUser = 17.0; const markerSize = 100.0; +const placeSize = 80.0; class MapView extends ConsumerStatefulWidget { final SpaceInfo? space; @@ -29,28 +33,48 @@ class MapView extends ConsumerStatefulWidget { class _MapScreenState extends ConsumerState { late MapViewNotifier notifier; final Completer _controller = Completer(); - final _center = const LatLng(21.2300467, 72.8359667); + final _cameraPosition = + const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); List _markers = []; + List _places = []; + + @override + void didUpdateWidget(covariant MapView oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.space?.space.id != widget.space?.space.id) { + setState(() { + _markers.clear(); + _places.clear(); + }); + } + } @override Widget build(BuildContext context) { + _observeMapCameraPosition(); + _observeNavigation(); _observeMarkerChange(); + _observeMemberPlace(context); notifier = ref.watch(mapViewStateProvider.notifier); final state = ref.watch(mapViewStateProvider); + print('${_markers.length}, ${_places.length}'); + return Stack( children: [ Center( child: GoogleMap( onMapCreated: _onMapCreated, - initialCameraPosition: CameraPosition(target: _center, zoom: 5.0), + initialCameraPosition: _cameraPosition, + compassEnabled: false, zoomControlsEnabled: false, tiltGesturesEnabled: false, myLocationButtonEnabled: false, - compassEnabled: false, mapToolbarEnabled: false, + buildingsEnabled: false, markers: _markers.toSet(), + circles: _places.toSet(), ), ), Positioned( @@ -61,8 +85,9 @@ class _MapScreenState extends ConsumerState { members: state.userInfo, selectedUser: state.selectedUser, isEnabled: !state.loading, - onAddMemberTap: () => - notifier.onAddMemberTap(widget.space!.space.id), + onAddMemberTap: () { + notifier.onAddMemberTap(widget.space!.space.id); + }, onMemberTap: (member) { notifier.showMemberDetail(member); }, @@ -80,23 +105,63 @@ class _MapScreenState extends ConsumerState { _controller.complete(controller); } + void _observeMapCameraPosition() { + ref.listen(mapViewStateProvider.select((state) => state.defaultPosition), + (previous, next) async { + if (next != null) { + final GoogleMapController controller = await _controller.future; + await controller.animateCamera(CameraUpdate.newCameraPosition(next)); + } + }); + } + + void _observeNavigation() { + ref.listen( + mapViewStateProvider.select((state) => state.spaceInvitationCode), + (_, next) { + if (next.isNotEmpty) { + AppRoute.inviteCode( + code: next, spaceName: widget.space?.space.name ?? '') + .push(context); + } + }); + } + void _observeMarkerChange() { ref.listen(mapViewStateProvider.select((state) => state.markers), (_, next) { + print("XXX marker:${_markers}"); if (next.isNotEmpty) { for (final item in next) { - _buildMarkerIcon(item); + _buildMarker(item); } - } else { - setState(() { - _markers = []; - }); } }); } - void _buildMarkerIcon(UserMarker item) async { - final marker = await _customMarker( + void _observeMemberPlace(BuildContext context) { + ref.listen(mapViewStateProvider.select((state) => state.places), (_, next) { + if (next.isNotEmpty) { + print('XXX place:$_places'); + for (final place in next) { + final latLng = LatLng(place.latitude, place.longitude); + _placeMarker(place.id, latLng); + + _places.add(Circle( + circleId: CircleId(place.id), + fillColor: context.colorScheme.primary.withOpacity(0.4), + strokeColor: context.colorScheme.primary.withOpacity(0.6), + strokeWidth: 1, + center: latLng, + radius: place.radius, + )); + } + } + }); + } + + void _buildMarker(UserMarker item) async { + final marker = await _mapMarker( item.isSelected, item.userName, item.imageUrl, @@ -104,33 +169,37 @@ class _MapScreenState extends ConsumerState { ? context.colorScheme.secondary : context.colorScheme.surface, context.colorScheme.primary, + AppTextStyle.subtitle2.copyWith(color: context.colorScheme.onPrimary), ); setState(() { _markers.add( Marker( - markerId: MarkerId(item.userId), - position: LatLng(item.latitude, item.longitude), - anchor: const Offset(0.0, 1.0), - icon: marker, - ), + markerId: MarkerId(item.userId), + position: LatLng(item.latitude, item.longitude), + anchor: const Offset(0.0, 1.0), + icon: marker, + onTap: () { + notifier.onTapUserMarker(item.userId); + }), ); }); } - Future _customMarker( + Future _mapMarker( bool isSelected, String userName, String? imageUrl, Color markerBgColor, Color iconBgColor, + TextStyle textStyle, ) async { if (imageUrl != null && imageUrl.isNotEmpty) { - return await _userImageMarker( - userName, imageUrl, isSelected, markerBgColor, iconBgColor); + return await _userImageMarker(userName, imageUrl, isSelected, + markerBgColor, iconBgColor, textStyle); } else { - return await _userCharMarker( - isSelected, userName, imageUrl, markerBgColor, iconBgColor); + return await _userCharMarker(isSelected, userName, imageUrl, + markerBgColor, iconBgColor, textStyle); } } @@ -140,6 +209,7 @@ class _MapScreenState extends ConsumerState { String? imageUrl, Color markerBgColor, Color iconBgColor, + TextStyle textStyle, ) async { final pictureRecorder = ui.PictureRecorder(); final canvas = Canvas(pictureRecorder); @@ -156,7 +226,7 @@ class _MapScreenState extends ConsumerState { Paint()..color = markerBgColor, ); - _drawUserName(canvas, userName, markerSize, iconBgColor); + _drawUserName(canvas, userName, iconBgColor); final picture = pictureRecorder.endRecording(); final img = await picture.toImage(markerSize.toInt(), markerSize.toInt()); @@ -167,15 +237,11 @@ class _MapScreenState extends ConsumerState { return bitmapDescriptor; } - void _drawUserName( - Canvas canvas, String userName, double size, Color bgColor) { + void _drawUserName(Canvas canvas, String userName, Color bgColor) { final textPainter = TextPainter(textDirection: TextDirection.ltr); - canvas.drawCircle( - Offset(size / 2, size / 2), - 40, - Paint()..color = bgColor, - ); + canvas.drawCircle(const Offset(markerSize / 2, markerSize / 2), 40, + Paint()..color = bgColor); textPainter.text = TextSpan( text: userName.isNotEmpty ? userName[0] : '', @@ -185,8 +251,8 @@ class _MapScreenState extends ConsumerState { textPainter.paint( canvas, Offset( - (size - textPainter.width) / 2, - (size - textPainter.height) / 2, + (markerSize - textPainter.width) / 2, + (markerSize - textPainter.height) / 2, ), ); } @@ -197,65 +263,136 @@ class _MapScreenState extends ConsumerState { bool isSelected, Color markerBgColor, Color iconBgColor, + TextStyle textStyle, ) async { - final response = await http.get(Uri.parse(imageUrl)); - if (response.statusCode == 200) { - final bytes = response.bodyBytes; - final image = img.decodeImage(bytes)!; - final resizedImage = img.copyResize(image, width: 80, height: 80); + try { + final cacheManager = DefaultCacheManager(); + final file = await cacheManager.getSingleFile(imageUrl); + + final bytes = await file.readAsBytes(); + final image = img.decodeImage(bytes); + if (image != null) { + final resizedImage = img.copyResize(image, width: 80, height: 80); + + // Create a circular image + final circularImage = img.copyCropCircle(resizedImage); + + final byteData = ByteData.view( + Uint8List.fromList(img.encodePng(circularImage)).buffer, + ); + + // Create an Image from the ByteData + final codec = + await ui.instantiateImageCodec(byteData.buffer.asUint8List()); + final frame = await codec.getNextFrame(); + final uiImage = frame.image; + + // Prepare the canvas to draw the rounded rectangle and the image + final recorder = ui.PictureRecorder(); + final canvas = ui.Canvas( + recorder, + Rect.fromPoints( + const Offset(0, 0), const Offset(markerSize, markerSize))); + + // Draw the rounded rectangle + canvas.drawRRect( + RRect.fromRectAndCorners( + const Rect.fromLTWH(0.0, 0.0, markerSize, markerSize), + topLeft: const Radius.circular(40), + topRight: const Radius.circular(40), + bottomLeft: const Radius.circular(0), + bottomRight: const Radius.circular(40), + ), + Paint()..color = markerBgColor, + ); - // Create a circular image - final circularImage = img.copyCropCircle(resizedImage); + // Calculate the position to center the image + final double imageOffset = (markerSize - uiImage.width.toDouble()) / 2; + final Offset offset = Offset(imageOffset, imageOffset); - final byteData = ByteData.view( - Uint8List.fromList(img.encodePng(circularImage)).buffer, - ); + // Draw the image on the canvas centered + canvas.drawImage(uiImage, offset, Paint()..color = iconBgColor); - // Create an Image from the ByteData - final codec = - await ui.instantiateImageCodec(byteData.buffer.asUint8List()); - final frame = await codec.getNextFrame(); - final uiImage = frame.image; - - // Prepare the canvas to draw the rounded rectangle and the image - final recorder = ui.PictureRecorder(); - final canvas = ui.Canvas( - recorder, - Rect.fromPoints( - const Offset(0, 0), const Offset(markerSize, markerSize))); - - // Draw the rounded rectangle - canvas.drawRRect( - RRect.fromRectAndCorners( - const Rect.fromLTWH(0.0, 0.0, markerSize, markerSize), - topLeft: const Radius.circular(40), - topRight: const Radius.circular(40), - bottomLeft: const Radius.circular(0), - bottomRight: const Radius.circular(40), - ), - Paint()..color = markerBgColor, - ); + // End recording and create an image from the canvas + final picture = recorder.endRecording(); + final imgData = + await picture.toImage(markerSize.toInt(), markerSize.toInt()); + final data = await imgData.toByteData(format: ui.ImageByteFormat.png); + + final bitmapDescriptor = + BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); + + return bitmapDescriptor; + } + } catch (e) { + logger.e("Error while getting network image:", error: e); + } + return _userCharMarker( + isSelected, userName, imageUrl, markerBgColor, iconBgColor, textStyle); + } + + Future getImage(String assetPath) async { + final asset = await rootBundle.load(assetPath); + final icon = BitmapDescriptor.fromBytes(asset.buffer.asUint8List()); + return icon; + } - // Calculate the position to center the image - final double imageOffset = (markerSize - uiImage.width.toDouble()) / 2; - final Offset offset = Offset(imageOffset, imageOffset); + void _placeMarker(String placeId, LatLng latLng) async { + rootBundle + .load('assets/images/ic_place_marker_icon.png') + .then((ByteData data) { + ui + .instantiateImageCodec(data.buffer.asUint8List()) + .then((ui.Codec codec) { + codec.getNextFrame().then((ui.FrameInfo fi) { + _drawPlaceMarker(fi, placeId, latLng); + }); + }); + }); + } - // Draw the image on the canvas centered - canvas.drawImage(uiImage, offset, Paint()..color = iconBgColor); + Future getPlaceImage(String assetPath) async { + final asset = await rootBundle.load(assetPath); + final icon = BitmapDescriptor.fromBytes(asset.buffer.asUint8List(), + size: Size(5, 5)); + return icon; + } - // End recording and create an image from the canvas - final picture = recorder.endRecording(); - final imgData = - await picture.toImage(markerSize.toInt(), markerSize.toInt()); - final data = await imgData.toByteData(format: ui.ImageByteFormat.png); + void _drawPlaceMarker(ui.FrameInfo frameInfo, String placeId, LatLng latLng) { + final pictureRecorder = ui.PictureRecorder(); + final canvas = Canvas(pictureRecorder); + final paint = Paint()..color = Colors.white; - final bitmapDescriptor = - BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); + canvas.drawCircle( + const Offset(placeSize / 2, placeSize / 2), placeSize / 2, paint); - return bitmapDescriptor; - } else { - return _userCharMarker( - isSelected, userName, imageUrl, markerBgColor, iconBgColor); - } + paintImage( + canvas: canvas, + image: frameInfo.image, + rect: const Rect.fromLTWH(0, 0, placeSize, placeSize), + fit: BoxFit.contain, + ); + + pictureRecorder + .endRecording() + .toImage(placeSize.toInt(), placeSize.toInt()) + .then((ui.Image markerAsImage) { + markerAsImage + .toByteData(format: ui.ImageByteFormat.png) + .then((ByteData? byteData) { + if (byteData != null) { + final Uint8List uint8List = byteData.buffer.asUint8List(); + + setState(() { + _markers.add(Marker( + markerId: MarkerId(placeId), + position: latLng, + anchor: const Offset(0.5, 0.5), + icon: BitmapDescriptor.fromBytes(uint8List), + )); + }); + } + }); + }); } } diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index 4f375157..9085d492 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -3,43 +3,57 @@ import 'package:data/api/place/api_place.dart'; import 'package:data/log/logger.dart'; import 'package:data/service/place_service.dart'; import 'package:data/service/space_service.dart'; +import 'package:data/storage/app_preferences.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'map_view.dart'; + part 'map_view_model.freezed.dart'; final mapViewStateProvider = StateNotifierProvider.autoDispose((ref) { return MapViewNotifier( + ref.read(currentUserPod), ref.read(spaceServiceProvider), ref.read(placeServiceProvider), ); }); class MapViewNotifier extends StateNotifier { + final ApiUser? _currentUser; final SpaceService spaceService; final PlaceService placeService; - MapViewNotifier(this.spaceService, this.placeService) + MapViewNotifier(this._currentUser, this.spaceService, this.placeService) : super(const MapViewState()); - void onSelectedSpaceChange(String? spaceId) { - if (spaceId == null) { - state = state.copyWith(userInfo: [], places: []); - return; - } - state = state.copyWith(markers: []); + void loadData(String? spaceId) { + onSelectedSpaceChange(); + + if (spaceId == null) return; + listenMemberLocation(spaceId); listenPlaces(spaceId); } + void onSelectedSpaceChange() { + state = state.copyWith( + userInfo: [], + places: [], + markers: [], + defaultPosition: null, + selectedUser: null, + ); + } + void listenMemberLocation(String spaceId) async { try { state = state.copyWith(loading: true, selectedUser: null); spaceService.getMemberWithLocation(spaceId).listen((userInfo) { state = state.copyWith(userInfo: userInfo, loading: false); - getUserMarker(userInfo); + userMapPositions(userInfo); }); } catch (error, stack) { state = state.copyWith(loading: false, error: error); @@ -66,9 +80,13 @@ class MapViewNotifier extends StateNotifier { } } - void getUserMarker(List userInfo) { + void userMapPositions(List userInfo) { final List markers = []; for (final info in userInfo) { + if (info.user.id == _currentUser?.id) { + mapDefaultPosition(info); + } + if (info.location != null) { markers.add(UserMarker( userId: info.user.id, @@ -84,6 +102,15 @@ class MapViewNotifier extends StateNotifier { state = state.copyWith(markers: markers); } + void mapDefaultPosition(ApiUserInfo userInfo) { + final position = CameraPosition( + target: LatLng(userInfo.location?.latitude ?? 0.0, + userInfo.location?.longitude ?? 0.0), + zoom: defaultCameraZoom, + ); + state = state.copyWith(defaultPosition: position); + } + void onAddMemberTap(String spaceId) async { try { state = state.copyWith(fetchingInviteCode: true, spaceInvitationCode: ''); @@ -101,15 +128,22 @@ class MapViewNotifier extends StateNotifier { } void onDismissMemberDetail() { - state = state.copyWith(selectedUser: null); + state = state.copyWith(selectedUser: null, defaultPosition: null); onShowDetailUpdateUserMarker(null); - } void showMemberDetail(ApiUserInfo member) { final selectedMember = (state.selectedUser?.user.id == member.user.id) ? null : member; - state = state.copyWith(selectedUser: selectedMember); + final position = (selectedMember != null && selectedMember.location != null) + ? CameraPosition( + target: LatLng(selectedMember.location!.latitude, + selectedMember.location!.longitude), + zoom: defaultCameraZoomForSelectedUser) + : null; + + state = + state.copyWith(selectedUser: selectedMember, defaultPosition: position); onShowDetailUpdateUserMarker(member.user.id); } @@ -129,6 +163,11 @@ class MapViewNotifier extends StateNotifier { } state = state.copyWith(markers: updatedMarkers); } + + void onTapUserMarker(String userId) { + final user = state.userInfo.firstWhere((user) => user.user.id == userId); + showMemberDetail(user); + } } @freezed @@ -140,7 +179,7 @@ class MapViewState with _$MapViewState { @Default([]) List places, @Default([]) List markers, ApiUserInfo? selectedUser, - LatLng? defaultPosition, + CameraPosition? defaultPosition, @Default('') String spaceInvitationCode, Object? error, }) = _MapViewState; diff --git a/app/lib/ui/flow/home/map/map_view_model.freezed.dart b/app/lib/ui/flow/home/map/map_view_model.freezed.dart index 59fbfb61..15fe2e28 100644 --- a/app/lib/ui/flow/home/map/map_view_model.freezed.dart +++ b/app/lib/ui/flow/home/map/map_view_model.freezed.dart @@ -22,7 +22,7 @@ mixin _$MapViewState { List get places => throw _privateConstructorUsedError; List get markers => throw _privateConstructorUsedError; ApiUserInfo? get selectedUser => throw _privateConstructorUsedError; - LatLng? get defaultPosition => throw _privateConstructorUsedError; + CameraPosition? get defaultPosition => throw _privateConstructorUsedError; String get spaceInvitationCode => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; @@ -44,7 +44,7 @@ abstract class $MapViewStateCopyWith<$Res> { List places, List markers, ApiUserInfo? selectedUser, - LatLng? defaultPosition, + CameraPosition? defaultPosition, String spaceInvitationCode, Object? error}); @@ -102,7 +102,7 @@ class _$MapViewStateCopyWithImpl<$Res, $Val extends MapViewState> defaultPosition: freezed == defaultPosition ? _value.defaultPosition : defaultPosition // ignore: cast_nullable_to_non_nullable - as LatLng?, + as CameraPosition?, spaceInvitationCode: null == spaceInvitationCode ? _value.spaceInvitationCode : spaceInvitationCode // ignore: cast_nullable_to_non_nullable @@ -139,7 +139,7 @@ abstract class _$$MapViewStateImplCopyWith<$Res> List places, List markers, ApiUserInfo? selectedUser, - LatLng? defaultPosition, + CameraPosition? defaultPosition, String spaceInvitationCode, Object? error}); @@ -193,7 +193,7 @@ class __$$MapViewStateImplCopyWithImpl<$Res> defaultPosition: freezed == defaultPosition ? _value.defaultPosition : defaultPosition // ignore: cast_nullable_to_non_nullable - as LatLng?, + as CameraPosition?, spaceInvitationCode: null == spaceInvitationCode ? _value.spaceInvitationCode : spaceInvitationCode // ignore: cast_nullable_to_non_nullable @@ -256,7 +256,7 @@ class _$MapViewStateImpl implements _MapViewState { @override final ApiUserInfo? selectedUser; @override - final LatLng? defaultPosition; + final CameraPosition? defaultPosition; @override @JsonKey() final String spaceInvitationCode; @@ -316,7 +316,7 @@ abstract class _MapViewState implements MapViewState { final List places, final List markers, final ApiUserInfo? selectedUser, - final LatLng? defaultPosition, + final CameraPosition? defaultPosition, final String spaceInvitationCode, final Object? error}) = _$MapViewStateImpl; @@ -333,7 +333,7 @@ abstract class _MapViewState implements MapViewState { @override ApiUserInfo? get selectedUser; @override - LatLng? get defaultPosition; + CameraPosition? get defaultPosition; @override String get spaceInvitationCode; @override diff --git a/app/pubspec.lock b/app/pubspec.lock index 4b85bb56..4f256269 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -510,7 +510,7 @@ packages: source: sdk version: "0.0.0" flutter_cache_manager: - dependency: transitive + dependency: "direct main" description: name: flutter_cache_manager sha256: "395d6b7831f21f3b989ebedbb785545932adb9afe2622c1ffacf7f4b53a7e544" diff --git a/app/pubspec.yaml b/app/pubspec.yaml index ac528ca6..0fc1b0bb 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -70,6 +70,7 @@ dependencies: flutter_svg: ^2.0.9 # picker canopas_country_picker: ^0.0.4 + flutter_cache_manager: ^3.3.2 dev_dependencies: From 97b300f9c2950dcb4aca9a1430ed842db74b7e39 Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 14 Jun 2024 15:59:58 +0530 Subject: [PATCH 05/65] Fix place and marker --- app/ios/Runner/AppDelegate.swift | 10 +++++----- app/ios/Runner/Info.plist | 2 -- app/lib/ui/flow/home/map/map_view.dart | 8 -------- app/lib/ui/flow/home/map/map_view_model.dart | 4 ++-- 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/app/ios/Runner/AppDelegate.swift b/app/ios/Runner/AppDelegate.swift index a55043ce..fb55820e 100644 --- a/app/ios/Runner/AppDelegate.swift +++ b/app/ios/Runner/AppDelegate.swift @@ -7,13 +7,13 @@ import Flutter _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - GMSServices.provideAPIKey(getMapKey()) +// GMSServices.provideAPIKey(getMapKey()) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } - func getMapKey() -> String { - let mapApiKey = Bundle.main.object(forInfoDictionaryKey: "MapApiKey") as? String - return mapApiKey ?? "" - } +// func getMapKey() -> String { +// let mapApiKey = Bundle.main.object(forInfoDictionaryKey: "MapApiKey") as? String +// return mapApiKey ?? "" +// } } diff --git a/app/ios/Runner/Info.plist b/app/ios/Runner/Info.plist index d39c96b3..a31e8613 100644 --- a/app/ios/Runner/Info.plist +++ b/app/ios/Runner/Info.plist @@ -58,7 +58,5 @@ App requires permission to access photos NSCameraUsageDescription App requires permission to access camera - MapApiKey - AIzaSyDbaJSVGU4Jkhd_V_e9esorzh_8yykh160 diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index 8830509c..fc32d8d0 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -130,7 +130,6 @@ class _MapScreenState extends ConsumerState { void _observeMarkerChange() { ref.listen(mapViewStateProvider.select((state) => state.markers), (_, next) { - print("XXX marker:${_markers}"); if (next.isNotEmpty) { for (final item in next) { _buildMarker(item); @@ -142,7 +141,6 @@ class _MapScreenState extends ConsumerState { void _observeMemberPlace(BuildContext context) { ref.listen(mapViewStateProvider.select((state) => state.places), (_, next) { if (next.isNotEmpty) { - print('XXX place:$_places'); for (final place in next) { final latLng = LatLng(place.latitude, place.longitude); _placeMarker(place.id, latLng); @@ -331,12 +329,6 @@ class _MapScreenState extends ConsumerState { isSelected, userName, imageUrl, markerBgColor, iconBgColor, textStyle); } - Future getImage(String assetPath) async { - final asset = await rootBundle.load(assetPath); - final icon = BitmapDescriptor.fromBytes(asset.buffer.asUint8List()); - return icon; - } - void _placeMarker(String placeId, LatLng latLng) async { rootBundle .load('assets/images/ic_place_marker_icon.png') diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index 9085d492..8c3a8902 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -84,7 +84,7 @@ class MapViewNotifier extends StateNotifier { final List markers = []; for (final info in userInfo) { if (info.user.id == _currentUser?.id) { - mapDefaultPosition(info); + mapCameraPosition(info); } if (info.location != null) { @@ -102,7 +102,7 @@ class MapViewNotifier extends StateNotifier { state = state.copyWith(markers: markers); } - void mapDefaultPosition(ApiUserInfo userInfo) { + void mapCameraPosition(ApiUserInfo userInfo) { final position = CameraPosition( target: LatLng(userInfo.location?.latitude ?? 0.0, userInfo.location?.longitude ?? 0.0), From a29125ae148f19c658c606e2c9555eec7236f11d Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 14 Jun 2024 16:20:37 +0530 Subject: [PATCH 06/65] Fix lint --- .../flow/home/map/components/space_user_footer.dart | 11 +++++++---- app/lib/ui/flow/home/map/map_view.dart | 13 ++----------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/app/lib/ui/flow/home/map/components/space_user_footer.dart b/app/lib/ui/flow/home/map/components/space_user_footer.dart index 43a5b03f..5618cb06 100644 --- a/app/lib/ui/flow/home/map/components/space_user_footer.dart +++ b/app/lib/ui/flow/home/map/components/space_user_footer.dart @@ -47,10 +47,13 @@ class _SpaceUserFooterState extends State { child: Column( children: [ _mapControlBtn(context), - SelectedMemberDetailView( - userInfo: widget.selectedUser, - onDismiss: widget.onDismiss, - onTapTimeline: widget.onTapTimeline, + AnimatedContainer( + duration: const Duration(milliseconds: 200), + child: SelectedMemberDetailView( + userInfo: widget.selectedUser, + onDismiss: widget.onDismiss, + onTapTimeline: widget.onTapTimeline, + ), ), Visibility( visible: widget.isEnabled && diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index fc32d8d0..b03d0e06 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -35,8 +35,8 @@ class _MapScreenState extends ConsumerState { final Completer _controller = Completer(); final _cameraPosition = const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); - List _markers = []; - List _places = []; + final List _markers = []; + final List _places = []; @override void didUpdateWidget(covariant MapView oldWidget) { @@ -59,8 +59,6 @@ class _MapScreenState extends ConsumerState { notifier = ref.watch(mapViewStateProvider.notifier); final state = ref.watch(mapViewStateProvider); - print('${_markers.length}, ${_places.length}'); - return Stack( children: [ Center( @@ -343,13 +341,6 @@ class _MapScreenState extends ConsumerState { }); } - Future getPlaceImage(String assetPath) async { - final asset = await rootBundle.load(assetPath); - final icon = BitmapDescriptor.fromBytes(asset.buffer.asUint8List(), - size: Size(5, 5)); - return icon; - } - void _drawPlaceMarker(ui.FrameInfo frameInfo, String placeId, LatLng latLng) { final pictureRecorder = ui.PictureRecorder(); final canvas = Canvas(pictureRecorder); From f1e78dc53e7fe3ef0903a13d8f7df10a1dc4fe11 Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 14 Jun 2024 18:32:21 +0530 Subject: [PATCH 07/65] Fix build --- .github/workflows/android_build.yml | 1 + app/android/app/build.gradle | 9 +++++- .../ui/components/user_battery_status.dart | 2 +- .../map/components/space_user_footer.dart | 31 ++++++++++++++----- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index 249af3f0..db9766cc 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -54,6 +54,7 @@ jobs: APKSIGN_KEYSTORE_PASS: ${{ secrets.APKSIGN_KEYSTORE_PASS }} APKSIGN_KEY_ALIAS: ${{ secrets.APKSIGN_KEY_ALIAS }} APKSIGN_KEY_PASS: ${{ secrets.APKSIGN_KEY_PASS }} + MAPS_API_KEY: ${{ secrets.MAPS_API_KEY }} run: | echo $APKSIGN_KEYSTORE_BASE64 | base64 -di > release.keystore diff --git a/app/android/app/build.gradle b/app/android/app/build.gradle index 2761a282..88cd1dc5 100644 --- a/app/android/app/build.gradle +++ b/app/android/app/build.gradle @@ -52,7 +52,14 @@ android { versionName flutterVersionName multiDexEnabled true - manifestPlaceholders += [MAPS_API_KEY: localProperties.getProperty('MAPS_API_KEY')] + def mapsApiKey = System.getenv('MAPS_API_KEY') + if (mapsApiKey != null) { + manifestPlaceholders += [MAPS_API_KEY: mapsApiKey] + } else if (localProperties.containsKey('MAPS_API_KEY')) { + manifestPlaceholders += [MAPS_API_KEY: localProperties.getProperty('MAPS_API_KEY')] + } else { + manifestPlaceholders += [MAPS_API_KEY: ''] + } } signingConfigs { diff --git a/app/lib/ui/components/user_battery_status.dart b/app/lib/ui/components/user_battery_status.dart index 0148731f..6387f11f 100644 --- a/app/lib/ui/components/user_battery_status.dart +++ b/app/lib/ui/components/user_battery_status.dart @@ -38,7 +38,7 @@ class UserBatteryStatus extends StatelessWidget { colorFilter: ColorFilter.mode(color, BlendMode.srcATop), ), Text( - '$batteryPct%', + '${batteryPct.toInt()}%', style: AppTextStyle.caption .copyWith(color: context.colorScheme.textPrimary), ) diff --git a/app/lib/ui/flow/home/map/components/space_user_footer.dart b/app/lib/ui/flow/home/map/components/space_user_footer.dart index 5618cb06..12f79522 100644 --- a/app/lib/ui/flow/home/map/components/space_user_footer.dart +++ b/app/lib/ui/flow/home/map/components/space_user_footer.dart @@ -47,13 +47,30 @@ class _SpaceUserFooterState extends State { child: Column( children: [ _mapControlBtn(context), - AnimatedContainer( - duration: const Duration(milliseconds: 200), - child: SelectedMemberDetailView( - userInfo: widget.selectedUser, - onDismiss: widget.onDismiss, - onTapTimeline: widget.onTapTimeline, - ), + + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + transitionBuilder: (Widget child, Animation animation) { + return SlideTransition( + position: Tween( + begin: const Offset(0.0, 1.0), + end: const Offset(0.0, 0.0), + ).animate(animation), + child: ScaleTransition( + scale: animation, + child: child), + ); + }, + child: widget.selectedUser != null + ? SelectedMemberDetailView( + key: const ValueKey('detailView'), + userInfo: widget.selectedUser, + onDismiss: widget.onDismiss, + onTapTimeline: widget.onTapTimeline, + ) + : const SizedBox.shrink( + key: ValueKey('emptyBox'), + ), ), Visibility( visible: widget.isEnabled && From d59ff7ea5f6bc2184a134bffa16ae5654c43eb76 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 17 Jun 2024 14:27:37 +0530 Subject: [PATCH 08/65] Fix map lag and place remove issue --- app/lib/ui/flow/home/home_screen.dart | 32 ++-- app/lib/ui/flow/home/map/map_view.dart | 155 ++++++++---------- app/lib/ui/flow/home/map/map_view_model.dart | 44 ++++- .../flow/home/map/map_view_model.freezed.dart | 16 +- 4 files changed, 129 insertions(+), 118 deletions(-) diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index 64a3fb79..73245aa3 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -73,30 +73,30 @@ class _HomeScreenState extends ConsumerState { void _observeNavigation(HomeViewState state) { ref.listen( homeViewStateProvider.select((state) => state.spaceInvitationCode), - (_, next) { - if (next.isNotEmpty) { - AppRoute.inviteCode( + (_, next) { + if (next.isNotEmpty) { + AppRoute.inviteCode( code: next, spaceName: state.selectedSpace?.space.name ?? '') - .push(context); - } - }); + .push(context); + } + }); } void _observeError() { ref.listen(homeViewStateProvider.select((state) => state.error), - (previous, next) { - if (next != null) { - showErrorSnackBar(context, next.toString()); - } - }); + (previous, next) { + if (next != null) { + showErrorSnackBar(context, next.toString()); + } + }); } void _observeSelectedSpace() { ref.listen(homeViewStateProvider.select((state) => state.selectedSpace), - (previous, next) { - if (previous?.space.id != next?.space.id) { - mapNotifier.loadData(next?.space.id); - } - }); + (previous, next) { + if (previous?.space.id != next?.space.id) { + mapNotifier.loadData(next?.space.id); + } + }); } } diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index b03d0e06..412bdf6f 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -2,13 +2,10 @@ import 'dart:async'; import 'dart:ui' as ui; import 'package:data/api/space/space_models.dart'; -import 'package:data/log/logger.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:image/image.dart' as img; import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/text/app_text_dart.dart'; @@ -35,6 +32,7 @@ class _MapScreenState extends ConsumerState { final Completer _controller = Completer(); final _cameraPosition = const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); + final List _markers = []; final List _places = []; @@ -71,8 +69,8 @@ class _MapScreenState extends ConsumerState { myLocationButtonEnabled: false, mapToolbarEnabled: false, buildingsEnabled: false, - markers: _markers.toSet(), circles: _places.toSet(), + markers: _markers.toSet(), ), ), Positioned( @@ -138,21 +136,27 @@ class _MapScreenState extends ConsumerState { void _observeMemberPlace(BuildContext context) { ref.listen(mapViewStateProvider.select((state) => state.places), (_, next) { - if (next.isNotEmpty) { - for (final place in next) { - final latLng = LatLng(place.latitude, place.longitude); - _placeMarker(place.id, latLng); - - _places.add(Circle( - circleId: CircleId(place.id), - fillColor: context.colorScheme.primary.withOpacity(0.4), - strokeColor: context.colorScheme.primary.withOpacity(0.6), - strokeWidth: 1, - center: latLng, - radius: place.radius, - )); + setState(() { + _places.clear(); + _markers + .removeWhere((marker) => marker.markerId.value.startsWith('place')); + + if (next.isNotEmpty) { + for (final place in next) { + final latLng = LatLng(place.latitude, place.longitude); + _placeMarker(place.id, latLng); + + _places.add(Circle( + circleId: CircleId(place.id), + fillColor: context.colorScheme.primary.withOpacity(0.4), + strokeColor: context.colorScheme.primary.withOpacity(0.6), + strokeWidth: 1, + center: latLng, + radius: place.radius, + )); + } } - } + }); }); } @@ -185,24 +189,23 @@ class _MapScreenState extends ConsumerState { Future _mapMarker( bool isSelected, String userName, - String? imageUrl, + ui.Image? imageUrl, Color markerBgColor, Color iconBgColor, TextStyle textStyle, ) async { - if (imageUrl != null && imageUrl.isNotEmpty) { + if (imageUrl != null) { return await _userImageMarker(userName, imageUrl, isSelected, markerBgColor, iconBgColor, textStyle); } else { - return await _userCharMarker(isSelected, userName, imageUrl, - markerBgColor, iconBgColor, textStyle); + return await _userCharMarker( + isSelected, userName, markerBgColor, iconBgColor, textStyle); } } Future _userCharMarker( bool isSelected, String userName, - String? imageUrl, Color markerBgColor, Color iconBgColor, TextStyle textStyle, @@ -255,76 +258,48 @@ class _MapScreenState extends ConsumerState { Future _userImageMarker( String userName, - String imageUrl, + ui.Image uiImage, bool isSelected, Color markerBgColor, Color iconBgColor, TextStyle textStyle, ) async { - try { - final cacheManager = DefaultCacheManager(); - final file = await cacheManager.getSingleFile(imageUrl); - - final bytes = await file.readAsBytes(); - final image = img.decodeImage(bytes); - if (image != null) { - final resizedImage = img.copyResize(image, width: 80, height: 80); - - // Create a circular image - final circularImage = img.copyCropCircle(resizedImage); - - final byteData = ByteData.view( - Uint8List.fromList(img.encodePng(circularImage)).buffer, - ); - - // Create an Image from the ByteData - final codec = - await ui.instantiateImageCodec(byteData.buffer.asUint8List()); - final frame = await codec.getNextFrame(); - final uiImage = frame.image; - - // Prepare the canvas to draw the rounded rectangle and the image - final recorder = ui.PictureRecorder(); - final canvas = ui.Canvas( - recorder, - Rect.fromPoints( - const Offset(0, 0), const Offset(markerSize, markerSize))); - - // Draw the rounded rectangle - canvas.drawRRect( - RRect.fromRectAndCorners( - const Rect.fromLTWH(0.0, 0.0, markerSize, markerSize), - topLeft: const Radius.circular(40), - topRight: const Radius.circular(40), - bottomLeft: const Radius.circular(0), - bottomRight: const Radius.circular(40), - ), - Paint()..color = markerBgColor, - ); + // Prepare the canvas to draw the rounded rectangle and the image + final recorder = ui.PictureRecorder(); + final canvas = ui.Canvas( + recorder, + Rect.fromPoints( + const Offset(0, 0), const Offset(markerSize, markerSize))); + + // Draw the rounded rectangle + canvas.drawRRect( + RRect.fromRectAndCorners( + const Rect.fromLTWH(0.0, 0.0, markerSize, markerSize), + topLeft: const Radius.circular(40), + topRight: const Radius.circular(40), + bottomLeft: const Radius.circular(0), + bottomRight: const Radius.circular(40), + ), + Paint()..color = markerBgColor, + ); - // Calculate the position to center the image - final double imageOffset = (markerSize - uiImage.width.toDouble()) / 2; - final Offset offset = Offset(imageOffset, imageOffset); + // Calculate the position to center the image + final double imageOffset = (markerSize - uiImage.width.toDouble()) / 2; + final Offset offset = Offset(imageOffset, imageOffset); - // Draw the image on the canvas centered - canvas.drawImage(uiImage, offset, Paint()..color = iconBgColor); + // Draw the image on the canvas centered + canvas.drawImage(uiImage, offset, Paint()..color = iconBgColor); - // End recording and create an image from the canvas - final picture = recorder.endRecording(); - final imgData = - await picture.toImage(markerSize.toInt(), markerSize.toInt()); - final data = await imgData.toByteData(format: ui.ImageByteFormat.png); + // End recording and create an image from the canvas + final picture = recorder.endRecording(); + final imgData = + await picture.toImage(markerSize.toInt(), markerSize.toInt()); + final data = await imgData.toByteData(format: ui.ImageByteFormat.png); - final bitmapDescriptor = - BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); + final bitmapDescriptor = + BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); - return bitmapDescriptor; - } - } catch (e) { - logger.e("Error while getting network image:", error: e); - } - return _userCharMarker( - isSelected, userName, imageUrl, markerBgColor, iconBgColor, textStyle); + return bitmapDescriptor; } void _placeMarker(String placeId, LatLng latLng) async { @@ -366,14 +341,12 @@ class _MapScreenState extends ConsumerState { if (byteData != null) { final Uint8List uint8List = byteData.buffer.asUint8List(); - setState(() { - _markers.add(Marker( - markerId: MarkerId(placeId), - position: latLng, - anchor: const Offset(0.5, 0.5), - icon: BitmapDescriptor.fromBytes(uint8List), - )); - }); + _markers.add(Marker( + markerId: MarkerId('place-$placeId'), + position: latLng, + anchor: const Offset(0.5, 0.5), + icon: BitmapDescriptor.fromBytes(uint8List), + )); } }); }); diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index 8c3a8902..fdc7af4c 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -1,12 +1,18 @@ +import 'dart:typed_data'; +import 'dart:ui' as ui; + import 'package:data/api/auth/auth_models.dart'; import 'package:data/api/place/api_place.dart'; import 'package:data/log/logger.dart'; import 'package:data/service/place_service.dart'; import 'package:data/service/space_service.dart'; import 'package:data/storage/app_preferences.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:image/image.dart' as img; import 'map_view.dart'; @@ -80,7 +86,7 @@ class MapViewNotifier extends StateNotifier { } } - void userMapPositions(List userInfo) { + void userMapPositions(List userInfo) async { final List markers = []; for (final info in userInfo) { if (info.user.id == _currentUser?.id) { @@ -91,7 +97,7 @@ class MapViewNotifier extends StateNotifier { markers.add(UserMarker( userId: info.user.id, userName: info.user.fullName, - imageUrl: info.user.profile_image, + imageUrl: await _convertUrlToImage(info.user.profile_image), latitude: info.location!.latitude, longitude: info.location!.longitude, isSelected: false, @@ -102,6 +108,38 @@ class MapViewNotifier extends StateNotifier { state = state.copyWith(markers: markers); } + Future _convertUrlToImage(String? imageUrl) async { + if (imageUrl == null || imageUrl.isEmpty) return null; + + try { + final cacheManager = DefaultCacheManager(); + final file = await cacheManager.getSingleFile(imageUrl); + + final bytes = await file.readAsBytes(); + final image = img.decodeImage(bytes); + if (image != null) { + final resizedImage = img.copyResize( + image, + width: placeSize.toInt(), + height: placeSize.toInt(), + ); + final circularImage = img.copyCropCircle(resizedImage); + + final byteData = ByteData.view( + Uint8List.fromList(img.encodePng(circularImage)).buffer, + ); + + final codec = + await ui.instantiateImageCodec(byteData.buffer.asUint8List()); + final frame = await codec.getNextFrame(); + return frame.image; + } + } catch (e) { + debugPrint("Error while getting network image: $e"); + } + return null; + } + void mapCameraPosition(ApiUserInfo userInfo) { final position = CameraPosition( target: LatLng(userInfo.location?.latitude ?? 0.0, @@ -190,7 +228,7 @@ class UserMarker with _$UserMarker { const factory UserMarker({ required String userId, required String userName, - required String? imageUrl, + required ui.Image? imageUrl, required double latitude, required double longitude, required bool isSelected, diff --git a/app/lib/ui/flow/home/map/map_view_model.freezed.dart b/app/lib/ui/flow/home/map/map_view_model.freezed.dart index 15fe2e28..ce3f33ca 100644 --- a/app/lib/ui/flow/home/map/map_view_model.freezed.dart +++ b/app/lib/ui/flow/home/map/map_view_model.freezed.dart @@ -348,7 +348,7 @@ abstract class _MapViewState implements MapViewState { mixin _$UserMarker { String get userId => throw _privateConstructorUsedError; String get userName => throw _privateConstructorUsedError; - String? get imageUrl => throw _privateConstructorUsedError; + ui.Image? get imageUrl => throw _privateConstructorUsedError; double get latitude => throw _privateConstructorUsedError; double get longitude => throw _privateConstructorUsedError; bool get isSelected => throw _privateConstructorUsedError; @@ -367,7 +367,7 @@ abstract class $UserMarkerCopyWith<$Res> { $Res call( {String userId, String userName, - String? imageUrl, + ui.Image? imageUrl, double latitude, double longitude, bool isSelected}); @@ -405,7 +405,7 @@ class _$UserMarkerCopyWithImpl<$Res, $Val extends UserMarker> imageUrl: freezed == imageUrl ? _value.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable - as String?, + as ui.Image?, latitude: null == latitude ? _value.latitude : latitude // ignore: cast_nullable_to_non_nullable @@ -433,7 +433,7 @@ abstract class _$$UserMarkerImplCopyWith<$Res> $Res call( {String userId, String userName, - String? imageUrl, + ui.Image? imageUrl, double latitude, double longitude, bool isSelected}); @@ -469,7 +469,7 @@ class __$$UserMarkerImplCopyWithImpl<$Res> imageUrl: freezed == imageUrl ? _value.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable - as String?, + as ui.Image?, latitude: null == latitude ? _value.latitude : latitude // ignore: cast_nullable_to_non_nullable @@ -502,7 +502,7 @@ class _$UserMarkerImpl implements _UserMarker { @override final String userName; @override - final String? imageUrl; + final ui.Image? imageUrl; @override final double latitude; @override @@ -548,7 +548,7 @@ abstract class _UserMarker implements UserMarker { const factory _UserMarker( {required final String userId, required final String userName, - required final String? imageUrl, + required final ui.Image? imageUrl, required final double latitude, required final double longitude, required final bool isSelected}) = _$UserMarkerImpl; @@ -558,7 +558,7 @@ abstract class _UserMarker implements UserMarker { @override String get userName; @override - String? get imageUrl; + ui.Image? get imageUrl; @override double get latitude; @override From 7f180664dc2deaf2c8dc56758fb7065edd21100b Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 17 Jun 2024 16:07:35 +0530 Subject: [PATCH 09/65] Fix map dark and light mode style --- app/lib/ui/flow/home/map/map_view.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index 412bdf6f..108afafc 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -57,6 +57,7 @@ class _MapScreenState extends ConsumerState { notifier = ref.watch(mapViewStateProvider.notifier); final state = ref.watch(mapViewStateProvider); + _updateMapStyle(context.brightness == Brightness.dark); return Stack( children: [ Center( @@ -101,6 +102,17 @@ class _MapScreenState extends ConsumerState { _controller.complete(controller); } + void _updateMapStyle(bool isDarkMode) async { + final controller = await _controller.future; + if (isDarkMode) { + final style = + await rootBundle.loadString('assets/map/map_theme_night.json'); + controller.setMapStyle(style); + } else { + controller.setMapStyle(null); + } + } + void _observeMapCameraPosition() { ref.listen(mapViewStateProvider.select((state) => state.defaultPosition), (previous, next) async { From 81711428d0136967f4f19415188e8653e760de07 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 19 Jun 2024 16:52:27 +0530 Subject: [PATCH 10/65] Fix user permission --- app/android/app/src/main/AndroidManifest.xml | 7 +- app/android/build.gradle | 2 +- app/assets/locales/app_en.arb | 31 ++- app/ios/Podfile | 16 ++ app/ios/Runner/Info.plist | 12 + .../extenstions/lat_lng_extenstion.dart | 31 +-- app/lib/ui/app_route.dart | 22 +- app/lib/ui/components/permission_dialog.dart | 72 ++++++ app/lib/ui/flow/home/home_screen.dart | 63 +++-- .../ui/flow/home/home_screen_viewmodel.dart | 25 +- .../home/home_screen_viewmodel.freezed.dart | 36 ++- .../map/components/space_user_footer.dart | 14 +- app/lib/ui/flow/home/map/map_view.dart | 149 ++++++++++-- app/lib/ui/flow/home/map/map_view_model.dart | 37 ++- .../permission/enable_permission_view.dart | 190 +++++++++++++++ .../enable_permission_view_model.dart | 72 ++++++ .../enable_permission_view_model.freezed.dart | 229 ++++++++++++++++++ app/pubspec.lock | 96 ++++++++ app/pubspec.yaml | 6 +- data/.flutter-plugins | 60 +++-- data/.flutter-plugins-dependencies | 2 +- data/lib/service/permission_service.dart | 70 ++++++ data/pubspec.yaml | 2 + style/lib/button/primary_button.dart | 85 ++++++- 24 files changed, 1218 insertions(+), 111 deletions(-) create mode 100644 app/lib/ui/components/permission_dialog.dart create mode 100644 app/lib/ui/flow/permission/enable_permission_view.dart create mode 100644 app/lib/ui/flow/permission/enable_permission_view_model.dart create mode 100644 app/lib/ui/flow/permission/enable_permission_view_model.freezed.dart create mode 100644 data/lib/service/permission_service.dart diff --git a/app/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml index e16638af..b276d897 100644 --- a/app/android/app/src/main/AndroidManifest.xml +++ b/app/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,11 @@ - - + + + + + Select allow all the time", + "enable_notification_access_title": "Notification Access", + "enable_notification_access_sun_title": "Stay connected and receive timely updates by enabling notification permission for check-ins, alerts, and messages from your trusted one.", + "enable_permission_footer": "We prioritize the security of your information and want to assure you that we do not share your data with any third-party entities.", + "enable_location_prompt_title": "Location access required", + "enable_location_prompt_sub_title_1": "YourSpace’s location-sharing feature works correctly when it can access your location all the time. This ensures it gives you accurate, real-time updates.", + "enable_location_prompt_sub_title_2": "Go to settings > Allow all the time", + "enable_location_service_title": "Turn on location/GPS", + "enable_location_service_message": "Your location/GPS setting must be turned on for YourSpace to work. Please turn on location/GPS in the settings.", + + "permission_footer_title": "Stay closed to your loved one.", + "permission_footer_missing_location_permission_title": "Location sharing is currently not possible.", + "permission_footer_subtitle": "Allow YourSpace to access your location data.", + "permission_footer_location_off_subtitle": "Device location/GPS is off. Please turn it on!", + "permission_footer_missing_location_permission_subtitle": "Some permissions are missing - grant access.", + + "battery_optimization_dialog_title":"Turn off Battery Optimization for Location Sharing", + "battery_optimization_dialog_message": "For location sharing feature to work properly for your Spaces, turn off Battery Optimization in your phone settings for the YourSpace app. This won't affect your other apps.", + "battery_optimization_dialog_btn_change_now":"Change now" } \ No newline at end of file diff --git a/app/ios/Podfile b/app/ios/Podfile index d97f17e2..83cb6d83 100644 --- a/app/ios/Podfile +++ b/app/ios/Podfile @@ -40,5 +40,21 @@ end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) + + # Start of the permission_handler configuration + target.build_configurations.each do |config| + + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ + '$(inherited)', + + ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse] + 'PERMISSION_LOCATION=1', + 'PERMISSION_LOCATION_WHENINUSE=0', + + ## dart: PermissionGroup.notification + 'PERMISSION_NOTIFICATIONS=1', + + ] + end end end diff --git a/app/ios/Runner/Info.plist b/app/ios/Runner/Info.plist index a31e8613..b7a4378a 100644 --- a/app/ios/Runner/Info.plist +++ b/app/ios/Runner/Info.plist @@ -41,6 +41,18 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + NSLocationWhenInUseUsageDescription + We need your location to provide better services. + NSLocationAlwaysUsageDescription + We need your location to provide background services. + NSLocationAlwaysAndWhenInUseUsageDescription + We need your location to provide services when the app is both in use and in the background. + UIBackgroundModes + + location + fetch + processing + CADisableMinimumFrameDurationOnPhone UIApplicationSupportsIndirectInputEvents diff --git a/app/lib/domain/extenstions/lat_lng_extenstion.dart b/app/lib/domain/extenstions/lat_lng_extenstion.dart index a8b16779..d39d98af 100644 --- a/app/lib/domain/extenstions/lat_lng_extenstion.dart +++ b/app/lib/domain/extenstions/lat_lng_extenstion.dart @@ -20,26 +20,27 @@ extension LatLngExtensions on LatLng { if (placeMarks.isNotEmpty) { var streets = placeMarks .map((placeMark) => placeMark.street) - .where((street) => street != null); + .where((street) => street != null) + .where((street) => + street!.toLowerCase() != + placeMarks.last.locality?.toLowerCase()) + .where((street) => !street!.contains('+')); - streets = streets.where((street) => - street!.toLowerCase() != placeMarks.last.locality!.toLowerCase()); - - streets = streets.where((street) => !street!.contains('+')); address += streets.join(', '); - address += ', ${placeMarks.reversed.last.subLocality ?? ''}'; - address += ', ${placeMarks.reversed.last.locality ?? ''}'; - address += ', ${placeMarks.reversed.last.subAdministrativeArea ?? ''}'; - address += ', ${placeMarks.reversed.last.administrativeArea ?? ''}'; - address += ', ${placeMarks.reversed.last.postalCode ?? ''}'; - address += ', ${placeMarks.reversed.last.country ?? ''}'; - } + final lastPlaceMark = placeMarks.reversed.last; + address += ', ${lastPlaceMark.subLocality ?? ''}'; + address += ', ${lastPlaceMark.locality ?? ''}'; + address += ', ${lastPlaceMark.subAdministrativeArea ?? ''}'; + address += ', ${lastPlaceMark.administrativeArea ?? ''}'; + address += ', ${lastPlaceMark.postalCode ?? ''}'; + address += ', ${lastPlaceMark.country ?? ''}'; - _cachedLatLng = LatLng(latitude, longitude); - _cachedAddress = address; + _cachedLatLng = LatLng(latitude, longitude); + _cachedAddress = address; - return address; + return address; + } } catch (e) { logger.e('GetAddress: Error while getting address', error: e); } diff --git a/app/lib/ui/app_route.dart b/app/lib/ui/app_route.dart index 4b8e2f17..2aad74cc 100644 --- a/app/lib/ui/app_route.dart +++ b/app/lib/ui/app_route.dart @@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:go_router/go_router.dart'; import 'package:yourspace_flutter/ui/flow/auth/sign_in/phone/verification/phone_verification_screen.dart'; import 'package:yourspace_flutter/ui/flow/onboard/pick_name_screen.dart'; +import 'package:yourspace_flutter/ui/flow/permission/enable_permission_view.dart'; import 'package:yourspace_flutter/ui/flow/setting/contact_support/contact_support_screen.dart'; import 'package:yourspace_flutter/ui/flow/setting/profile/profile_screen.dart'; import 'package:yourspace_flutter/ui/flow/setting/setting_screen.dart'; @@ -24,6 +25,7 @@ class AppRoute { static const pathProfile = '/profile'; static const pathEditSpace = '/space'; static const pathContactSupport = '/contact-support'; + static const pathEnablePermission = '/enable-permission'; final String path; final String? name; @@ -110,7 +112,7 @@ class AppRoute { ); static AppRoute get pickName => AppRoute( - "/pick-name", + "/pick-name", builder: (_) => const PickNameScreen(), ); @@ -126,16 +128,19 @@ class AppRoute { AppRoute(pathCreateSpace, builder: (_) => const CreateSpace()); static AppRoute get joinSpace => - AppRoute(pathJoinSpace, builder: (_) => const JoinSpace()); + AppRoute(pathJoinSpace, builder: (_) => const JoinSpace()); - static AppRoute inviteCode({ - required String code, required String spaceName}) { + static AppRoute inviteCode( + {required String code, required String spaceName}) { return AppRoute( pathInviteCode, builder: (_) => InviteCode(spaceName: spaceName, inviteCode: code), ); } + static AppRoute get enablePermission => AppRoute(pathEnablePermission, + builder: (_) => const EnablePermissionView()); + static AppRoute get setting => AppRoute(pathCreateSpace, builder: (_) => const SettingScreen()); @@ -149,8 +154,8 @@ class AppRoute { ); } - static AppRoute get contactSupport => - AppRoute(pathContactSupport, builder: (_) => const ContactSupportScreen()); + static AppRoute get contactSupport => AppRoute(pathContactSupport, + builder: (_) => const ContactSupportScreen()); static final routes = [ GoRoute( @@ -191,7 +196,6 @@ class AppRoute { ? const PhoneVerificationScreen('', '') : state.widget(context); }), - GoRoute( path: pathCreateSpace, builder: (context, state) => state.widget(context), @@ -220,6 +224,10 @@ class AppRoute { path: pathContactSupport, builder: (context, state) => state.widget(context), ), + GoRoute( + path: pathEnablePermission, + builder: (context, state) => state.widget(context), + ), ]; } diff --git a/app/lib/ui/components/permission_dialog.dart b/app/lib/ui/components/permission_dialog.dart new file mode 100644 index 00000000..3ef6f19c --- /dev/null +++ b/app/lib/ui/components/permission_dialog.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:style/button/primary_button.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; + +class PermissionDialog extends StatelessWidget { + final String title; + final String subTitle1; + final String? subTitle2; + final String? dismissBtn; + final String? confirmBtn; + final VoidCallback onDismiss; + final VoidCallback goToSettings; + + const PermissionDialog({ + super.key, + required this.title, + required this.subTitle1, + this.subTitle2, + this.dismissBtn, + this.confirmBtn, + required this.onDismiss, + required this.goToSettings, + }); + + @override + Widget build(BuildContext context) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + title: Text( + title, + textAlign: TextAlign.center, + style: AppTextStyle.header3, + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + subTitle1, + textAlign: TextAlign.center, + style: AppTextStyle.body1 + .copyWith(color: context.colorScheme.textDisabled), + ), + if (subTitle2 != null) ...[ + const SizedBox(height: 24), + Text( + subTitle2!, + textAlign: TextAlign.center, + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.textDisabled), + ), + ], + ], + ), + actions: [ + PrimaryButton(confirmBtn ?? context.l10n.common_go_to_setting, + onPressed: goToSettings), + if (dismissBtn != null) ...[ + const SizedBox(height: 16), + OutlinedPrimaryButton( + dismissBtn!, + onPressed: onDismiss, + foreground: context.colorScheme.primary, + ), + ], + ], + ); + } +} diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index 73245aa3..034c49ea 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:style/extenstions/context_extenstions.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; import 'package:yourspace_flutter/domain/extenstions/widget_extensions.dart'; import 'package:yourspace_flutter/ui/app_route.dart'; import 'package:yourspace_flutter/ui/components/app_page.dart'; import 'package:yourspace_flutter/ui/components/error_snakebar.dart'; +import 'package:yourspace_flutter/ui/components/permission_dialog.dart'; import 'package:yourspace_flutter/ui/components/resume_detector.dart'; import 'package:yourspace_flutter/ui/flow/home/home_screen_viewmodel.dart'; import 'package:yourspace_flutter/ui/flow/home/map/map_view_model.dart'; @@ -38,6 +40,7 @@ class _HomeScreenState extends ConsumerState { _observeNavigation(state); _observeError(); _observeSelectedSpace(); + _observeShowBatteryDialog(context); mapNotifier = ref.watch(mapViewStateProvider.notifier); @@ -45,6 +48,8 @@ class _HomeScreenState extends ConsumerState { body: ResumeDetector( onResume: () { notifier.getAllSpace(); + notifier.showBatteryOptimizationDialog(); + mapNotifier.checkLocationAndNotificationPermission(); }, child: _body(context, state), ), @@ -73,30 +78,56 @@ class _HomeScreenState extends ConsumerState { void _observeNavigation(HomeViewState state) { ref.listen( homeViewStateProvider.select((state) => state.spaceInvitationCode), - (_, next) { - if (next.isNotEmpty) { - AppRoute.inviteCode( + (_, next) { + if (next.isNotEmpty) { + AppRoute.inviteCode( code: next, spaceName: state.selectedSpace?.space.name ?? '') - .push(context); - } - }); + .push(context); + } + }); } void _observeError() { ref.listen(homeViewStateProvider.select((state) => state.error), - (previous, next) { - if (next != null) { - showErrorSnackBar(context, next.toString()); - } - }); + (previous, next) { + if (next != null) { + showErrorSnackBar(context, next.toString()); + } + }); } void _observeSelectedSpace() { ref.listen(homeViewStateProvider.select((state) => state.selectedSpace), - (previous, next) { - if (previous?.space.id != next?.space.id) { - mapNotifier.loadData(next?.space.id); - } - }); + (previous, next) { + if (previous?.space.id != next?.space.id) { + mapNotifier.loadData(next?.space.id); + } + }); + } + + void _observeShowBatteryDialog(BuildContext context) { + ref.listen(homeViewStateProvider.select((state) => state.showBatteryDialog), + (_, next) { + if (next != null) { + showDialog( + context: context, + builder: (context) { + return PermissionDialog( + title: context.l10n.battery_optimization_dialog_title, + subTitle1: context.l10n.battery_optimization_dialog_message, + confirmBtn: + context.l10n.battery_optimization_dialog_btn_change_now, + dismissBtn: context.l10n.common_cancel, + onDismiss: () { + Navigator.of(context).pop(); + }, + goToSettings: () { + notifier.requestIgnoreBatteryOptimizations(); + Navigator.of(context).pop(); + }, + ); + }); + } + }); } } diff --git a/app/lib/ui/flow/home/home_screen_viewmodel.dart b/app/lib/ui/flow/home/home_screen_viewmodel.dart index a867494e..25fad07c 100644 --- a/app/lib/ui/flow/home/home_screen_viewmodel.dart +++ b/app/lib/ui/flow/home/home_screen_viewmodel.dart @@ -1,5 +1,6 @@ import 'package:data/api/space/space_models.dart'; import 'package:data/log/logger.dart'; +import 'package:data/service/permission_service.dart'; import 'package:data/service/space_service.dart'; import 'package:data/storage/app_preferences.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -12,14 +13,17 @@ final homeViewStateProvider = (ref) => HomeViewNotifier( ref.read(spaceServiceProvider), ref.read(currentUserSessionJsonPod.notifier), + ref.read(permissionServiceProvider), ), ); class HomeViewNotifier extends StateNotifier { final SpaceService spaceService; + final PermissionService permissionService; final StateController _currentSpaceIdController; - HomeViewNotifier(this.spaceService, this._currentSpaceIdController) + HomeViewNotifier( + this.spaceService, this._currentSpaceIdController, this.permissionService) : super(const HomeViewState()); String? get currentSpaceId => _currentSpaceIdController.state; @@ -83,6 +87,24 @@ class HomeViewNotifier extends StateNotifier { currentSpaceId = space.space.id; } } + + void showBatteryOptimizationDialog() async { + // We don't want to show prompt immediately after user opens the app + await Future.delayed(const Duration(seconds: 1)); + + final isBatteryOptimization = + await permissionService.isBatteryOptimizationEnabled(); + final isBackgroundEnabled = + await permissionService.isBackgroundLocationPermissionGranted(); + + if (!isBatteryOptimization && isBackgroundEnabled) { + state = state.copyWith(showBatteryDialog: DateTime.now()); + } + } + + void requestIgnoreBatteryOptimizations() async { + await permissionService.requestIgnoreBatteryOptimizations(); + } } @freezed @@ -96,5 +118,6 @@ class HomeViewState with _$HomeViewState { @Default('') String spaceInvitationCode, @Default([]) List spaceList, Object? error, + DateTime? showBatteryDialog, }) = _HomeViewState; } diff --git a/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart b/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart index 6fc49f77..041c8582 100644 --- a/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart +++ b/app/lib/ui/flow/home/home_screen_viewmodel.freezed.dart @@ -24,6 +24,7 @@ mixin _$HomeViewState { String get spaceInvitationCode => throw _privateConstructorUsedError; List get spaceList => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; + DateTime? get showBatteryDialog => throw _privateConstructorUsedError; @JsonKey(ignore: true) $HomeViewStateCopyWith get copyWith => @@ -44,7 +45,8 @@ abstract class $HomeViewStateCopyWith<$Res> { SpaceInfo? selectedSpace, String spaceInvitationCode, List spaceList, - Object? error}); + Object? error, + DateTime? showBatteryDialog}); $SpaceInfoCopyWith<$Res>? get selectedSpace; } @@ -70,6 +72,7 @@ class _$HomeViewStateCopyWithImpl<$Res, $Val extends HomeViewState> Object? spaceInvitationCode = null, Object? spaceList = null, Object? error = freezed, + Object? showBatteryDialog = freezed, }) { return _then(_value.copyWith( allowSave: null == allowSave @@ -101,6 +104,10 @@ class _$HomeViewStateCopyWithImpl<$Res, $Val extends HomeViewState> : spaceList // ignore: cast_nullable_to_non_nullable as List, error: freezed == error ? _value.error : error, + showBatteryDialog: freezed == showBatteryDialog + ? _value.showBatteryDialog + : showBatteryDialog // ignore: cast_nullable_to_non_nullable + as DateTime?, ) as $Val); } @@ -133,7 +140,8 @@ abstract class _$$HomeViewStateImplCopyWith<$Res> SpaceInfo? selectedSpace, String spaceInvitationCode, List spaceList, - Object? error}); + Object? error, + DateTime? showBatteryDialog}); @override $SpaceInfoCopyWith<$Res>? get selectedSpace; @@ -158,6 +166,7 @@ class __$$HomeViewStateImplCopyWithImpl<$Res> Object? spaceInvitationCode = null, Object? spaceList = null, Object? error = freezed, + Object? showBatteryDialog = freezed, }) { return _then(_$HomeViewStateImpl( allowSave: null == allowSave @@ -189,6 +198,10 @@ class __$$HomeViewStateImplCopyWithImpl<$Res> : spaceList // ignore: cast_nullable_to_non_nullable as List, error: freezed == error ? _value.error : error, + showBatteryDialog: freezed == showBatteryDialog + ? _value.showBatteryDialog + : showBatteryDialog // ignore: cast_nullable_to_non_nullable + as DateTime?, )); } } @@ -204,7 +217,8 @@ class _$HomeViewStateImpl implements _HomeViewState { this.selectedSpace, this.spaceInvitationCode = '', final List spaceList = const [], - this.error}) + this.error, + this.showBatteryDialog}) : _spaceList = spaceList; @override @@ -235,10 +249,12 @@ class _$HomeViewStateImpl implements _HomeViewState { @override final Object? error; + @override + final DateTime? showBatteryDialog; @override String toString() { - return 'HomeViewState(allowSave: $allowSave, isCreating: $isCreating, loading: $loading, fetchingInviteCode: $fetchingInviteCode, selectedSpace: $selectedSpace, spaceInvitationCode: $spaceInvitationCode, spaceList: $spaceList, error: $error)'; + return 'HomeViewState(allowSave: $allowSave, isCreating: $isCreating, loading: $loading, fetchingInviteCode: $fetchingInviteCode, selectedSpace: $selectedSpace, spaceInvitationCode: $spaceInvitationCode, spaceList: $spaceList, error: $error, showBatteryDialog: $showBatteryDialog)'; } @override @@ -259,7 +275,9 @@ class _$HomeViewStateImpl implements _HomeViewState { other.spaceInvitationCode == spaceInvitationCode) && const DeepCollectionEquality() .equals(other._spaceList, _spaceList) && - const DeepCollectionEquality().equals(other.error, error)); + const DeepCollectionEquality().equals(other.error, error) && + (identical(other.showBatteryDialog, showBatteryDialog) || + other.showBatteryDialog == showBatteryDialog)); } @override @@ -272,7 +290,8 @@ class _$HomeViewStateImpl implements _HomeViewState { selectedSpace, spaceInvitationCode, const DeepCollectionEquality().hash(_spaceList), - const DeepCollectionEquality().hash(error)); + const DeepCollectionEquality().hash(error), + showBatteryDialog); @JsonKey(ignore: true) @override @@ -290,7 +309,8 @@ abstract class _HomeViewState implements HomeViewState { final SpaceInfo? selectedSpace, final String spaceInvitationCode, final List spaceList, - final Object? error}) = _$HomeViewStateImpl; + final Object? error, + final DateTime? showBatteryDialog}) = _$HomeViewStateImpl; @override bool get allowSave; @@ -309,6 +329,8 @@ abstract class _HomeViewState implements HomeViewState { @override Object? get error; @override + DateTime? get showBatteryDialog; + @override @JsonKey(ignore: true) _$$HomeViewStateImplCopyWith<_$HomeViewStateImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/app/lib/ui/flow/home/map/components/space_user_footer.dart b/app/lib/ui/flow/home/map/components/space_user_footer.dart index 12f79522..1af867a8 100644 --- a/app/lib/ui/flow/home/map/components/space_user_footer.dart +++ b/app/lib/ui/flow/home/map/components/space_user_footer.dart @@ -43,11 +43,10 @@ class _SpaceUserFooterState extends State { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16), + padding: const EdgeInsets.only(top: 24, left: 16, right: 16, bottom: 16), child: Column( children: [ _mapControlBtn(context), - AnimatedSwitcher( duration: const Duration(milliseconds: 300), transitionBuilder: (Widget child, Animation animation) { @@ -56,9 +55,7 @@ class _SpaceUserFooterState extends State { begin: const Offset(0.0, 1.0), end: const Offset(0.0, 0.0), ).animate(animation), - child: ScaleTransition( - scale: animation, - child: child), + child: ScaleTransition(scale: animation, child: child), ); }, child: widget.selectedUser != null @@ -97,7 +94,6 @@ class _SpaceUserFooterState extends State { iconSize: 24, foreground: context.colorScheme.primary, background: context.colorScheme.surface, - visibility: true, onTap: widget.onRelocateTap, ), const SizedBox(height: 8), @@ -107,9 +103,9 @@ class _SpaceUserFooterState extends State { iconSize: 24, foreground: context.colorScheme.onPrimary, background: context.colorScheme.primary, - visibility: true, onTap: widget.onPlacesTap, - ) + ), + const SizedBox(height: 16) ], ), ); @@ -121,7 +117,7 @@ class _SpaceUserFooterState extends State { required double iconSize, required Color foreground, required Color background, - required bool visibility, + bool visibility = true, required Function() onTap, }) { return Visibility( diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index 108afafc..1b0b6176 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -6,10 +6,14 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:style/animation/on_tap_scale.dart'; import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; import '../../../app_route.dart'; +import '../../../components/permission_dialog.dart'; import 'components/space_user_footer.dart'; import 'map_view_model.dart'; @@ -52,6 +56,7 @@ class _MapScreenState extends ConsumerState { _observeMapCameraPosition(); _observeNavigation(); _observeMarkerChange(); + _observeShowEnableLocationPrompt(context); _observeMemberPlace(context); notifier = ref.watch(mapViewStateProvider.notifier); @@ -74,30 +79,114 @@ class _MapScreenState extends ConsumerState { markers: _markers.toSet(), ), ), - Positioned( - bottom: 0, - left: 0, - right: 0, - child: SpaceUserFooter( - members: state.userInfo, - selectedUser: state.selectedUser, - isEnabled: !state.loading, - onAddMemberTap: () { - notifier.onAddMemberTap(widget.space!.space.id); - }, - onMemberTap: (member) { - notifier.showMemberDetail(member); - }, - onRelocateTap: () {}, - onPlacesTap: () {}, - onDismiss: () => notifier.onDismissMemberDetail(), - onTapTimeline: () {}, - ), + Positioned(bottom: 0, left: 0, right: 0, child: _bottomFooters(state)), + ], + ); + } + + Widget _bottomFooters(MapViewState state) { + final enabled = !state.hasLocationEnabled || + !state.hasLocationServiceEnabled || + !state.hasNotificationEnabled; + + return Column( + children: [ + SpaceUserFooter( + members: state.userInfo, + selectedUser: state.selectedUser, + isEnabled: !state.loading, + onAddMemberTap: () { + notifier.onAddMemberTap(widget.space!.space.id); + }, + onMemberTap: (member) { + notifier.showMemberDetail(member); + }, + onRelocateTap: () {}, + onPlacesTap: () {}, + onDismiss: () => notifier.onDismissMemberDetail(), + onTapTimeline: () {}, ), + Visibility(visible: enabled, child: _permissionFooter(state)) ], ); } + Widget _permissionFooter(MapViewState state) { + final locationEnabled = + state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; + final (title, subTitle) = _permissionFooterContent(state); + + return OnTapScale( + onTap: () { + (!locationEnabled) + ? notifier.showEnableLocationDialog() + : AppRoute.enablePermission.push(context); + }, + child: Container( + padding: const EdgeInsets.all(16), + width: double.infinity, + color: !locationEnabled + ? context.colorScheme.alert + : context.colorScheme.secondary, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: AppTextStyle.subtitle1.copyWith( + color: context.colorScheme.textInversePrimary, + ), + ), + const SizedBox(height: 4), + Text( + subTitle, + style: AppTextStyle.body1.copyWith( + color: context.colorScheme.textInverseDisabled, + ), + ) + ], + ), + Icon( + Icons.arrow_forward_ios_rounded, + size: 16, + color: context.colorScheme.textInversePrimary, + ) + ], + ), + ), + ); + } + + (String, String) _permissionFooterContent(MapViewState state) { + final locationEnabled = + state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; + + String title = ''; + String subTitle = ''; + + if (!state.hasLocationEnabled) { + title = context.l10n.permission_footer_missing_location_permission_title; + } else if (!state.hasNotificationEnabled) { + title = context.l10n.permission_footer_title; + } else { + title = context.l10n.permission_footer_missing_location_permission_title; + } + + if (!locationEnabled) { + subTitle = context.l10n.permission_footer_location_off_subtitle; + } else if (!state.hasFineLocationEnabled) { + subTitle = context.l10n.permission_footer_subtitle; + } else { + subTitle = + context.l10n.permission_footer_missing_location_permission_subtitle; + } + + return (title, subTitle); + } + void _onMapCreated(GoogleMapController controller) async { _controller.complete(controller); } @@ -146,6 +235,28 @@ class _MapScreenState extends ConsumerState { }); } + void _observeShowEnableLocationPrompt(BuildContext context) { + ref.listen(mapViewStateProvider.select((state) => state.showLocationDialog), + (_, next) { + if (next != null) { + showDialog( + context: context, + builder: (context) { + return PermissionDialog( + title: context.l10n.enable_location_service_title, + subTitle1: context.l10n.enable_location_service_message, + onDismiss: () {}, + goToSettings: () { + openAppSettings(); + Navigator.of(context).pop(); + }, + ); + }, + ); + } + }); + } + void _observeMemberPlace(BuildContext context) { ref.listen(mapViewStateProvider.select((state) => state.places), (_, next) { setState(() { diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index fdc7af4c..91d181af 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -4,6 +4,7 @@ import 'dart:ui' as ui; import 'package:data/api/auth/auth_models.dart'; import 'package:data/api/place/api_place.dart'; import 'package:data/log/logger.dart'; +import 'package:data/service/permission_service.dart'; import 'package:data/service/place_service.dart'; import 'package:data/service/space_service.dart'; import 'package:data/storage/app_preferences.dart'; @@ -24,6 +25,7 @@ final mapViewStateProvider = ref.read(currentUserPod), ref.read(spaceServiceProvider), ref.read(placeServiceProvider), + ref.read(permissionServiceProvider), ); }); @@ -31,9 +33,14 @@ class MapViewNotifier extends StateNotifier { final ApiUser? _currentUser; final SpaceService spaceService; final PlaceService placeService; + final PermissionService permissionService; - MapViewNotifier(this._currentUser, this.spaceService, this.placeService) - : super(const MapViewState()); + MapViewNotifier( + this._currentUser, + this.spaceService, + this.placeService, + this.permissionService, + ) : super(const MapViewState()); void loadData(String? spaceId) { onSelectedSpaceChange(); @@ -206,6 +213,27 @@ class MapViewNotifier extends StateNotifier { final user = state.userInfo.firstWhere((user) => user.user.id == userId); showMemberDetail(user); } + + void checkLocationAndNotificationPermission() async { + final isLocationEnabled = await permissionService.isLocationAlwaysEnabled(); + final isLocationServiceEnabled = + await permissionService.isLocationServiceEnabled(); + final isNotificationEnabled = + await permissionService.hasNotificationPermission(); + final isFineLocationPermission = + await permissionService.isLocationPermissionGranted(); + + state = state.copyWith( + hasLocationEnabled: isLocationEnabled, + hasLocationServiceEnabled: isLocationServiceEnabled, + hasNotificationEnabled: isNotificationEnabled, + hasFineLocationEnabled: isFineLocationPermission, + ); + } + + void showEnableLocationDialog() { + state = state.copyWith(showLocationDialog: DateTime.now()); + } } @freezed @@ -213,6 +241,10 @@ class MapViewState with _$MapViewState { const factory MapViewState({ @Default(false) loading, @Default(false) bool fetchingInviteCode, + @Default(false) bool hasLocationEnabled, + @Default(false) bool hasLocationServiceEnabled, + @Default(false) bool hasNotificationEnabled, + @Default(false) bool hasFineLocationEnabled, @Default([]) List userInfo, @Default([]) List places, @Default([]) List markers, @@ -220,6 +252,7 @@ class MapViewState with _$MapViewState { CameraPosition? defaultPosition, @Default('') String spaceInvitationCode, Object? error, + DateTime? showLocationDialog, }) = _MapViewState; } diff --git a/app/lib/ui/flow/permission/enable_permission_view.dart b/app/lib/ui/flow/permission/enable_permission_view.dart new file mode 100644 index 00000000..a9634e04 --- /dev/null +++ b/app/lib/ui/flow/permission/enable_permission_view.dart @@ -0,0 +1,190 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; +import 'package:yourspace_flutter/ui/components/app_page.dart'; +import 'package:yourspace_flutter/ui/flow/permission/enable_permission_view_model.dart'; + +import '../../components/error_snakebar.dart'; +import '../../components/permission_dialog.dart'; + +class EnablePermissionView extends ConsumerStatefulWidget { + const EnablePermissionView({super.key}); + + @override + ConsumerState createState() => + _EnablePermissionViewState(); +} + +class _EnablePermissionViewState extends ConsumerState + with WidgetsBindingObserver { + late PermissionViewNotifier notifier; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + notifier = ref.read(permissionStateProvider.notifier); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + if (state == AppLifecycleState.resumed) { + notifier.checkUserPermissions(); + } + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + _observeBackgroundLocationAccessBanner(context); + _observeShowLocationAccessPrompt(context); + return AppPage( + title: context.l10n.enable_permission_top_bar_text, + body: Builder(builder: (_) { + return _body(); + }), + ); + } + + Widget _body() { + final state = ref.watch(permissionStateProvider); + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + children: [ + Text( + context.l10n.enable_permission_screen_title, + style: AppTextStyle.body1.copyWith( + color: context.colorScheme.textDisabled, + ), + ), + const SizedBox(height: 40), + _permissionView( + title: context.l10n.enable_location_access_title, + subTitle: context.l10n.enable_location_access_sub_title, + buttonValue: state.isLocationGranted, + onTapRadio: notifier.requestLocationPermission, + ), + const SizedBox(height: 24), + _permissionView( + title: context.l10n.enable_background_location_access_title, + subTitle: context.l10n.enable_background_location_access_sub_title, + buttonValue: state.isBackGroundLocationGranted, + onTapRadio: notifier.requestBackgroundLocationPermission, + ), + const SizedBox(height: 24), + _permissionView( + title: context.l10n.enable_notification_access_title, + subTitle: context.l10n.enable_notification_access_sun_title, + buttonValue: state.isNotificationGranted, + onTapRadio: notifier.requestNotificationPermission, + ), + const Spacer(), + Padding( + padding: EdgeInsets.only( + top: 24, bottom: context.mediaQueryPadding.bottom + 16), + child: Text( + context.l10n.enable_permission_footer, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), + textAlign: TextAlign.center, + ), + ) + ], + ), + ); + } + + Widget _permissionView({ + required String title, + required String subTitle, + required bool buttonValue, + required VoidCallback onTapRadio, + }) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 24, + height: 24, + child: Radio( + value: true, + groupValue: buttonValue, + activeColor: context.colorScheme.primary, + onChanged: (value) { + onTapRadio(); + }, + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ), + const SizedBox(height: 8), + Text( + subTitle, + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.textDisabled), + ), + ], + ), + ) + ], + ); + } + + void _observeBackgroundLocationAccessBanner(BuildContext context) { + ref.listen(permissionStateProvider.select((state) => state.bgAction), + (_, next) { + if (next != null) { + showErrorSnackBar( + context, + context.l10n.enable_background_location_access_message_text, + ); + } + }); + } + + void _observeShowLocationAccessPrompt(BuildContext context) { + ref.listen( + permissionStateProvider.select((state) => state.showLocationPrompt), + (_, next) { + if (next != null) { + showDialog( + context: context, + builder: (context) { + return PermissionDialog( + title: context.l10n.enable_location_prompt_title, + subTitle1: context.l10n.enable_location_prompt_sub_title_1, + subTitle2: context.l10n.enable_location_prompt_sub_title_2, + onDismiss: () {}, + goToSettings: () { + _openAppSettingInfoScreen(); + Navigator.of(context).pop(); + }, + ); + }, + ); + } + }); + } + + void _openAppSettingInfoScreen() async { + await openAppSettings(); + } +} diff --git a/app/lib/ui/flow/permission/enable_permission_view_model.dart b/app/lib/ui/flow/permission/enable_permission_view_model.dart new file mode 100644 index 00000000..b03f42f7 --- /dev/null +++ b/app/lib/ui/flow/permission/enable_permission_view_model.dart @@ -0,0 +1,72 @@ +import 'package:data/service/permission_service.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:permission_handler/permission_handler.dart'; + +part 'enable_permission_view_model.freezed.dart'; + +final permissionStateProvider = StateNotifierProvider.autoDispose< + PermissionViewNotifier, PermissionViewState>((ref) { + return PermissionViewNotifier( + ref.read(permissionServiceProvider), + ); +}); + +class PermissionViewNotifier extends StateNotifier { + final PermissionService permissionService; + + PermissionViewNotifier(this.permissionService) + : super(const PermissionViewState()) { + checkUserPermissions(); + } + + void checkUserPermissions() async { + final isLocationGranted = + await permissionService.isLocationPermissionGranted(); + final isBackGroundLocationGranted = + await permissionService.isBackgroundLocationPermissionGranted(); + final isNotificationGranted = + await permissionService.hasNotificationPermission(); + + state = state.copyWith( + isLocationGranted: isLocationGranted, + isBackGroundLocationGranted: isBackGroundLocationGranted, + isNotificationGranted: isNotificationGranted, + ); + } + + Future requestLocationPermission() async { + final permissionState = await permissionService.requestLocationPermission(); + if (permissionState.isGranted) { + state = state.copyWith(isLocationGranted: true); + } else { + state = state.copyWith(showLocationPrompt: DateTime.now()); + } + } + + Future requestBackgroundLocationPermission() async { + if (state.isLocationGranted) { + final granted = + await permissionService.requestBackgroundLocationPermission(); + state = state.copyWith(isBackGroundLocationGranted: granted); + } else { + state = state.copyWith(bgAction: DateTime.now()); + } + } + + Future requestNotificationPermission() async { + final granted = await permissionService.requestNotificationPermission(); + state = state.copyWith(isNotificationGranted: granted); + } +} + +@freezed +class PermissionViewState with _$PermissionViewState { + const factory PermissionViewState({ + DateTime? bgAction, + DateTime? showLocationPrompt, + @Default(false) isLocationGranted, + @Default(false) isBackGroundLocationGranted, + @Default(false) isNotificationGranted, + }) = _PermissionViewState; +} diff --git a/app/lib/ui/flow/permission/enable_permission_view_model.freezed.dart b/app/lib/ui/flow/permission/enable_permission_view_model.freezed.dart new file mode 100644 index 00000000..11c6a47a --- /dev/null +++ b/app/lib/ui/flow/permission/enable_permission_view_model.freezed.dart @@ -0,0 +1,229 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'enable_permission_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$PermissionViewState { + DateTime? get bgAction => throw _privateConstructorUsedError; + DateTime? get showLocationPrompt => throw _privateConstructorUsedError; + dynamic get isLocationGranted => throw _privateConstructorUsedError; + dynamic get isBackGroundLocationGranted => throw _privateConstructorUsedError; + dynamic get isNotificationGranted => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $PermissionViewStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PermissionViewStateCopyWith<$Res> { + factory $PermissionViewStateCopyWith( + PermissionViewState value, $Res Function(PermissionViewState) then) = + _$PermissionViewStateCopyWithImpl<$Res, PermissionViewState>; + @useResult + $Res call( + {DateTime? bgAction, + DateTime? showLocationPrompt, + dynamic isLocationGranted, + dynamic isBackGroundLocationGranted, + dynamic isNotificationGranted}); +} + +/// @nodoc +class _$PermissionViewStateCopyWithImpl<$Res, $Val extends PermissionViewState> + implements $PermissionViewStateCopyWith<$Res> { + _$PermissionViewStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? bgAction = freezed, + Object? showLocationPrompt = freezed, + Object? isLocationGranted = freezed, + Object? isBackGroundLocationGranted = freezed, + Object? isNotificationGranted = freezed, + }) { + return _then(_value.copyWith( + bgAction: freezed == bgAction + ? _value.bgAction + : bgAction // ignore: cast_nullable_to_non_nullable + as DateTime?, + showLocationPrompt: freezed == showLocationPrompt + ? _value.showLocationPrompt + : showLocationPrompt // ignore: cast_nullable_to_non_nullable + as DateTime?, + isLocationGranted: freezed == isLocationGranted + ? _value.isLocationGranted + : isLocationGranted // ignore: cast_nullable_to_non_nullable + as dynamic, + isBackGroundLocationGranted: freezed == isBackGroundLocationGranted + ? _value.isBackGroundLocationGranted + : isBackGroundLocationGranted // ignore: cast_nullable_to_non_nullable + as dynamic, + isNotificationGranted: freezed == isNotificationGranted + ? _value.isNotificationGranted + : isNotificationGranted // ignore: cast_nullable_to_non_nullable + as dynamic, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$PermissionViewStateImplCopyWith<$Res> + implements $PermissionViewStateCopyWith<$Res> { + factory _$$PermissionViewStateImplCopyWith(_$PermissionViewStateImpl value, + $Res Function(_$PermissionViewStateImpl) then) = + __$$PermissionViewStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {DateTime? bgAction, + DateTime? showLocationPrompt, + dynamic isLocationGranted, + dynamic isBackGroundLocationGranted, + dynamic isNotificationGranted}); +} + +/// @nodoc +class __$$PermissionViewStateImplCopyWithImpl<$Res> + extends _$PermissionViewStateCopyWithImpl<$Res, _$PermissionViewStateImpl> + implements _$$PermissionViewStateImplCopyWith<$Res> { + __$$PermissionViewStateImplCopyWithImpl(_$PermissionViewStateImpl _value, + $Res Function(_$PermissionViewStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? bgAction = freezed, + Object? showLocationPrompt = freezed, + Object? isLocationGranted = freezed, + Object? isBackGroundLocationGranted = freezed, + Object? isNotificationGranted = freezed, + }) { + return _then(_$PermissionViewStateImpl( + bgAction: freezed == bgAction + ? _value.bgAction + : bgAction // ignore: cast_nullable_to_non_nullable + as DateTime?, + showLocationPrompt: freezed == showLocationPrompt + ? _value.showLocationPrompt + : showLocationPrompt // ignore: cast_nullable_to_non_nullable + as DateTime?, + isLocationGranted: freezed == isLocationGranted + ? _value.isLocationGranted! + : isLocationGranted, + isBackGroundLocationGranted: freezed == isBackGroundLocationGranted + ? _value.isBackGroundLocationGranted! + : isBackGroundLocationGranted, + isNotificationGranted: freezed == isNotificationGranted + ? _value.isNotificationGranted! + : isNotificationGranted, + )); + } +} + +/// @nodoc + +class _$PermissionViewStateImpl implements _PermissionViewState { + const _$PermissionViewStateImpl( + {this.bgAction, + this.showLocationPrompt, + this.isLocationGranted = false, + this.isBackGroundLocationGranted = false, + this.isNotificationGranted = false}); + + @override + final DateTime? bgAction; + @override + final DateTime? showLocationPrompt; + @override + @JsonKey() + final dynamic isLocationGranted; + @override + @JsonKey() + final dynamic isBackGroundLocationGranted; + @override + @JsonKey() + final dynamic isNotificationGranted; + + @override + String toString() { + return 'PermissionViewState(bgAction: $bgAction, showLocationPrompt: $showLocationPrompt, isLocationGranted: $isLocationGranted, isBackGroundLocationGranted: $isBackGroundLocationGranted, isNotificationGranted: $isNotificationGranted)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PermissionViewStateImpl && + (identical(other.bgAction, bgAction) || + other.bgAction == bgAction) && + (identical(other.showLocationPrompt, showLocationPrompt) || + other.showLocationPrompt == showLocationPrompt) && + const DeepCollectionEquality() + .equals(other.isLocationGranted, isLocationGranted) && + const DeepCollectionEquality().equals( + other.isBackGroundLocationGranted, + isBackGroundLocationGranted) && + const DeepCollectionEquality() + .equals(other.isNotificationGranted, isNotificationGranted)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + bgAction, + showLocationPrompt, + const DeepCollectionEquality().hash(isLocationGranted), + const DeepCollectionEquality().hash(isBackGroundLocationGranted), + const DeepCollectionEquality().hash(isNotificationGranted)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PermissionViewStateImplCopyWith<_$PermissionViewStateImpl> get copyWith => + __$$PermissionViewStateImplCopyWithImpl<_$PermissionViewStateImpl>( + this, _$identity); +} + +abstract class _PermissionViewState implements PermissionViewState { + const factory _PermissionViewState( + {final DateTime? bgAction, + final DateTime? showLocationPrompt, + final dynamic isLocationGranted, + final dynamic isBackGroundLocationGranted, + final dynamic isNotificationGranted}) = _$PermissionViewStateImpl; + + @override + DateTime? get bgAction; + @override + DateTime? get showLocationPrompt; + @override + dynamic get isLocationGranted; + @override + dynamic get isBackGroundLocationGranted; + @override + dynamic get isNotificationGranted; + @override + @JsonKey(ignore: true) + _$$PermissionViewStateImplCopyWith<_$PermissionViewStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/app/pubspec.lock b/app/pubspec.lock index 4f256269..b75d9f9f 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -660,6 +660,54 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "149876cc5207a0f5daf4fdd3bfcf0a0f27258b3fe95108fa084f527ad0568f1b" + url: "https://pub.dev" + source: hosted + version: "12.0.0" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: "00c7177a95823dd3ee35ef42fd8666cd27d219ae14cea472ac76a21dff43000b" + url: "https://pub.dev" + source: hosted + version: "4.6.0" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: bc2aca02423ad429cb0556121f56e60360a2b7d694c8570301d06ea0c00732fd + url: "https://pub.dev" + source: hosted + version: "2.3.7" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "386ce3d9cce47838355000070b1d0b13efb5bc430f8ecda7e9238c8409ace012" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: "7a22f400d831f924a89d931ba126a10e6b8b437f31e6b9311320435f3e1571bd" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "53da08937d07c24b0d9952eb57a3b474e29aae2abf9dd717f7e1230995f13f0e" + url: "https://pub.dev" + source: hosted + version: "0.2.3" glob: dependency: transitive description: @@ -1124,6 +1172,54 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" + url: "https://pub.dev" + source: hosted + version: "11.3.1" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: b29a799ca03be9f999aa6c39f7de5209482d638e6f857f6b93b0875c618b7e54 + url: "https://pub.dev" + source: hosted + version: "12.0.7" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0 + url: "https://pub.dev" + source: hosted + version: "9.4.5" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d" + url: "https://pub.dev" + source: hosted + version: "0.1.1" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20" + url: "https://pub.dev" + source: hosted + version: "4.2.1" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" petitparser: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 0fc1b0bb..1abc8ab7 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: flutter: sdk: flutter flutter_localizations: - sdk: flutter + sdk: flutter intl: any style: @@ -56,10 +56,13 @@ dependencies: fluttertoast: ^8.2.6 http: ^1.2.1 image: ^3.0.1 + flutter_cache_manager: ^3.3.2 + permission_handler: ^11.3.1 # map google_maps_flutter: ^2.2.8 geocoding: ^3.0.0 + geolocator: ^12.0.0 # auth firebase_auth: ^4.20.0 @@ -70,7 +73,6 @@ dependencies: flutter_svg: ^2.0.9 # picker canopas_country_picker: ^0.0.4 - flutter_cache_manager: ^3.3.2 dev_dependencies: diff --git a/data/.flutter-plugins b/data/.flutter-plugins index ce4daee3..fc05ec80 100644 --- a/data/.flutter-plugins +++ b/data/.flutter-plugins @@ -1,26 +1,36 @@ # This is a generated file; do not edit or check into version control. -cloud_firestore=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/ -cloud_firestore_web=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/ -cloud_functions=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/ -cloud_functions_web=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/ -device_info_plus=/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/ -firebase_auth=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/ -firebase_auth_web=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/ -firebase_core=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/ -firebase_core_web=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/ -firebase_storage=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/ -firebase_storage_web=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/ -flutter_timezone=/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/ -google_sign_in=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in-6.2.1/ -google_sign_in_android=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.23/ -google_sign_in_ios=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/ -google_sign_in_web=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+3/ -package_info_plus=/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/ -path_provider_linux=/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ -path_provider_windows=/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ -shared_preferences=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/ -shared_preferences_android=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/ -shared_preferences_foundation=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/ -shared_preferences_linux=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/ -shared_preferences_web=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/ -shared_preferences_windows=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/ +cloud_firestore=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/ +cloud_firestore_web=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/ +cloud_functions=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/ +cloud_functions_web=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/ +device_info_plus=/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/ +firebase_auth=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/ +firebase_auth_web=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/ +firebase_core=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/ +firebase_core_web=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/ +firebase_storage=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/ +firebase_storage_web=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/ +flutter_timezone=/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/ +geolocator=/home/kaushik/.pub-cache/hosted/pub.dev/geolocator-12.0.0/ +geolocator_android=/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_android-4.6.0/ +geolocator_apple=/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/ +geolocator_web=/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_web-4.0.0/ +geolocator_windows=/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_windows-0.2.3/ +google_sign_in=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in-6.2.1/ +google_sign_in_android=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/ +google_sign_in_ios=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/ +google_sign_in_web=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/ +package_info_plus=/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/ +path_provider_linux=/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ +path_provider_windows=/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ +permission_handler=/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler-11.3.1/ +permission_handler_android=/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_android-12.0.7/ +permission_handler_apple=/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_apple-9.4.5/ +permission_handler_html=/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_html-0.1.1/ +permission_handler_windows=/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_windows-0.2.1/ +shared_preferences=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/ +shared_preferences_android=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/ +shared_preferences_foundation=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/ +shared_preferences_linux=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/ +shared_preferences_web=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/ +shared_preferences_windows=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/ diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index 0d340917..7f9d07e4 100644 --- a/data/.flutter-plugins-dependencies +++ b/data/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.23/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"google_sign_in_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+3/","dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-06-06 12:12:52.852133","version":"3.22.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_apple-9.4.5/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_android-4.6.0/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_android-12.0.7/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"geolocator_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_windows-0.2.3/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_windows-0.2.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"geolocator_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_web-4.0.0/","dependencies":[]},{"name":"google_sign_in_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/","dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"permission_handler_html","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_html-0.1.1/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"geolocator","dependencies":["geolocator_android","geolocator_apple","geolocator_web","geolocator_windows"]},{"name":"geolocator_android","dependencies":[]},{"name":"geolocator_apple","dependencies":[]},{"name":"geolocator_web","dependencies":[]},{"name":"geolocator_windows","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_html","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_html","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-06-19 10:31:08.546107","version":"3.22.0"} \ No newline at end of file diff --git a/data/lib/service/permission_service.dart b/data/lib/service/permission_service.dart new file mode 100644 index 00000000..47293a84 --- /dev/null +++ b/data/lib/service/permission_service.dart @@ -0,0 +1,70 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:permission_handler/permission_handler.dart'; + +final permissionServiceProvider = Provider((ref) => const PermissionService()); + +class PermissionService { + const PermissionService(); + + Future isLocationPermissionGranted() async { + return await Permission.location.isGranted; + } + + Future requestLocationPermission() async { + return await Permission.location.request(); + } + + Future isBackgroundLocationPermissionGranted() async { + return await Permission.locationAlways.isGranted; + } + + Future requestBackgroundLocationPermission() async { + return await requestPermission(Permission.locationAlways); + } + + Future hasNotificationPermission() async { + return await Permission.notification.isGranted; + } + + Future requestNotificationPermission() async { + return await requestPermission(Permission.notification); + } + + Future isBatteryOptimizationEnabled() async { + return await Permission.ignoreBatteryOptimizations.isGranted; + } + + Future requestIgnoreBatteryOptimizations() async { + await Permission.ignoreBatteryOptimizations.request(); + } + + Future isLocationAlwaysEnabled() async { + final isLocationEnabled = await isLocationPermissionGranted(); + final isBackgroundEnabled = await isBackgroundLocationPermissionGranted(); + return (isLocationEnabled && isBackgroundEnabled); + } + + Future isLocationServiceEnabled() async { + return await Geolocator.isLocationServiceEnabled(); + } + + Future requestPermission(Permission permission) async { + final status = await permission.status; + + if (status.isDenied) { + final newStatus = await permission.request(); + if (newStatus.isDenied || newStatus.isPermanentlyDenied) { + await openAppSettings(); + return false; + } else { + return newStatus.isGranted; + } + } else if (status.isPermanentlyDenied) { + await openAppSettings(); + return false; + } else { + return status.isGranted; + } + } +} diff --git a/data/pubspec.yaml b/data/pubspec.yaml index ac77b219..96929166 100644 --- a/data/pubspec.yaml +++ b/data/pubspec.yaml @@ -23,6 +23,8 @@ dependencies: flutter_timezone: ^1.0.8 package_info_plus: ^8.0.0 uuid: ^4.4.0 + permission_handler: ^11.3.1 + geolocator: ^12.0.0 dev_dependencies: flutter_test: diff --git a/style/lib/button/primary_button.dart b/style/lib/button/primary_button.dart index 47e43dd1..f7dd62d4 100644 --- a/style/lib/button/primary_button.dart +++ b/style/lib/button/primary_button.dart @@ -18,11 +18,12 @@ class PrimaryButton extends StatelessWidget { final Function()? onPressed; final bool showIcon; - const PrimaryButton(this.text, { + const PrimaryButton( + this.text, { super.key, this.onPressed, this.edgeInsets = - const EdgeInsets.symmetric(vertical: 8.0, horizontal: 12.0), + const EdgeInsets.symmetric(vertical: 8.0, horizontal: 12.0), this.expanded = true, this.enabled = true, this.progress = false, @@ -71,9 +72,87 @@ class PrimaryButton extends StatelessWidget { child: Padding( padding: const EdgeInsets.only(right: 8), child: Icon( - Icons.delete_outline_rounded, color: context.colorScheme.alert, size: 20,), + Icons.delete_outline_rounded, + color: context.colorScheme.alert, + size: 20, + ), + ), + ), + Visibility( + visible: progress, + child: Padding( + padding: const EdgeInsets.only(right: 12), + child: AppProgressIndicator( + size: AppProgressIndicatorSize.small, + color: fgColor, + ), ), ), + Text( + text, + style: AppTextStyle.button.copyWith( + color: fgColor, + ), + ), + ], + ), + ), + ); + } +} + +class OutlinedPrimaryButton extends StatelessWidget { + final String text; + final EdgeInsets edgeInsets; + final bool expanded; + final bool progress; + final bool enabled; + final Color? foreground; + final Function()? onPressed; + + const OutlinedPrimaryButton( + this.text, { + super.key, + this.onPressed, + this.edgeInsets = + const EdgeInsets.symmetric(vertical: 8.0, horizontal: 12.0), + this.expanded = true, + this.enabled = true, + this.progress = false, + this.foreground, + }); + + @override + Widget build(BuildContext context) { + final AppColorScheme colorScheme = appColorSchemeOf(context); + final tappable = !progress && enabled; + + final fg = foreground ?? colorScheme.primary; + final fgColor = tappable + ? fg + : Color.alphaBlend(fg.withOpacity(0.5), colorScheme.surface); + + return OnTapScale( + onTap: () { + onPressed?.call(); + }, + enabled: tappable, + child: Container( + width: expanded ? double.infinity : null, + constraints: BoxConstraints( + minHeight: expanded ? 48 : 36, + minWidth: 88, + ), + padding: edgeInsets, + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all(color: colorScheme.primary, width: 1), + borderRadius: BorderRadius.circular(24), + ), + child: Row( + mainAxisSize: expanded ? MainAxisSize.max : MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ Visibility( visible: progress, child: Padding( From c59061dd540831380b3d147068a15e7451c9d432 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 19 Jun 2024 16:58:51 +0530 Subject: [PATCH 11/65] Fix lint --- .../flow/home/map/map_view_model.freezed.dart | 129 +++++++++++++++++- 1 file changed, 122 insertions(+), 7 deletions(-) diff --git a/app/lib/ui/flow/home/map/map_view_model.freezed.dart b/app/lib/ui/flow/home/map/map_view_model.freezed.dart index ce3f33ca..1c46e1df 100644 --- a/app/lib/ui/flow/home/map/map_view_model.freezed.dart +++ b/app/lib/ui/flow/home/map/map_view_model.freezed.dart @@ -18,6 +18,10 @@ final _privateConstructorUsedError = UnsupportedError( mixin _$MapViewState { dynamic get loading => throw _privateConstructorUsedError; bool get fetchingInviteCode => throw _privateConstructorUsedError; + bool get hasLocationEnabled => throw _privateConstructorUsedError; + bool get hasLocationServiceEnabled => throw _privateConstructorUsedError; + bool get hasNotificationEnabled => throw _privateConstructorUsedError; + bool get hasFineLocationEnabled => throw _privateConstructorUsedError; List get userInfo => throw _privateConstructorUsedError; List get places => throw _privateConstructorUsedError; List get markers => throw _privateConstructorUsedError; @@ -25,6 +29,7 @@ mixin _$MapViewState { CameraPosition? get defaultPosition => throw _privateConstructorUsedError; String get spaceInvitationCode => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; + DateTime? get showLocationDialog => throw _privateConstructorUsedError; @JsonKey(ignore: true) $MapViewStateCopyWith get copyWith => @@ -40,13 +45,18 @@ abstract class $MapViewStateCopyWith<$Res> { $Res call( {dynamic loading, bool fetchingInviteCode, + bool hasLocationEnabled, + bool hasLocationServiceEnabled, + bool hasNotificationEnabled, + bool hasFineLocationEnabled, List userInfo, List places, List markers, ApiUserInfo? selectedUser, CameraPosition? defaultPosition, String spaceInvitationCode, - Object? error}); + Object? error, + DateTime? showLocationDialog}); $ApiUserInfoCopyWith<$Res>? get selectedUser; } @@ -66,6 +76,10 @@ class _$MapViewStateCopyWithImpl<$Res, $Val extends MapViewState> $Res call({ Object? loading = freezed, Object? fetchingInviteCode = null, + Object? hasLocationEnabled = null, + Object? hasLocationServiceEnabled = null, + Object? hasNotificationEnabled = null, + Object? hasFineLocationEnabled = null, Object? userInfo = null, Object? places = null, Object? markers = null, @@ -73,6 +87,7 @@ class _$MapViewStateCopyWithImpl<$Res, $Val extends MapViewState> Object? defaultPosition = freezed, Object? spaceInvitationCode = null, Object? error = freezed, + Object? showLocationDialog = freezed, }) { return _then(_value.copyWith( loading: freezed == loading @@ -83,6 +98,22 @@ class _$MapViewStateCopyWithImpl<$Res, $Val extends MapViewState> ? _value.fetchingInviteCode : fetchingInviteCode // ignore: cast_nullable_to_non_nullable as bool, + hasLocationEnabled: null == hasLocationEnabled + ? _value.hasLocationEnabled + : hasLocationEnabled // ignore: cast_nullable_to_non_nullable + as bool, + hasLocationServiceEnabled: null == hasLocationServiceEnabled + ? _value.hasLocationServiceEnabled + : hasLocationServiceEnabled // ignore: cast_nullable_to_non_nullable + as bool, + hasNotificationEnabled: null == hasNotificationEnabled + ? _value.hasNotificationEnabled + : hasNotificationEnabled // ignore: cast_nullable_to_non_nullable + as bool, + hasFineLocationEnabled: null == hasFineLocationEnabled + ? _value.hasFineLocationEnabled + : hasFineLocationEnabled // ignore: cast_nullable_to_non_nullable + as bool, userInfo: null == userInfo ? _value.userInfo : userInfo // ignore: cast_nullable_to_non_nullable @@ -108,6 +139,10 @@ class _$MapViewStateCopyWithImpl<$Res, $Val extends MapViewState> : spaceInvitationCode // ignore: cast_nullable_to_non_nullable as String, error: freezed == error ? _value.error : error, + showLocationDialog: freezed == showLocationDialog + ? _value.showLocationDialog + : showLocationDialog // ignore: cast_nullable_to_non_nullable + as DateTime?, ) as $Val); } @@ -135,13 +170,18 @@ abstract class _$$MapViewStateImplCopyWith<$Res> $Res call( {dynamic loading, bool fetchingInviteCode, + bool hasLocationEnabled, + bool hasLocationServiceEnabled, + bool hasNotificationEnabled, + bool hasFineLocationEnabled, List userInfo, List places, List markers, ApiUserInfo? selectedUser, CameraPosition? defaultPosition, String spaceInvitationCode, - Object? error}); + Object? error, + DateTime? showLocationDialog}); @override $ApiUserInfoCopyWith<$Res>? get selectedUser; @@ -160,6 +200,10 @@ class __$$MapViewStateImplCopyWithImpl<$Res> $Res call({ Object? loading = freezed, Object? fetchingInviteCode = null, + Object? hasLocationEnabled = null, + Object? hasLocationServiceEnabled = null, + Object? hasNotificationEnabled = null, + Object? hasFineLocationEnabled = null, Object? userInfo = null, Object? places = null, Object? markers = null, @@ -167,6 +211,7 @@ class __$$MapViewStateImplCopyWithImpl<$Res> Object? defaultPosition = freezed, Object? spaceInvitationCode = null, Object? error = freezed, + Object? showLocationDialog = freezed, }) { return _then(_$MapViewStateImpl( loading: freezed == loading ? _value.loading! : loading, @@ -174,6 +219,22 @@ class __$$MapViewStateImplCopyWithImpl<$Res> ? _value.fetchingInviteCode : fetchingInviteCode // ignore: cast_nullable_to_non_nullable as bool, + hasLocationEnabled: null == hasLocationEnabled + ? _value.hasLocationEnabled + : hasLocationEnabled // ignore: cast_nullable_to_non_nullable + as bool, + hasLocationServiceEnabled: null == hasLocationServiceEnabled + ? _value.hasLocationServiceEnabled + : hasLocationServiceEnabled // ignore: cast_nullable_to_non_nullable + as bool, + hasNotificationEnabled: null == hasNotificationEnabled + ? _value.hasNotificationEnabled + : hasNotificationEnabled // ignore: cast_nullable_to_non_nullable + as bool, + hasFineLocationEnabled: null == hasFineLocationEnabled + ? _value.hasFineLocationEnabled + : hasFineLocationEnabled // ignore: cast_nullable_to_non_nullable + as bool, userInfo: null == userInfo ? _value._userInfo : userInfo // ignore: cast_nullable_to_non_nullable @@ -199,6 +260,10 @@ class __$$MapViewStateImplCopyWithImpl<$Res> : spaceInvitationCode // ignore: cast_nullable_to_non_nullable as String, error: freezed == error ? _value.error : error, + showLocationDialog: freezed == showLocationDialog + ? _value.showLocationDialog + : showLocationDialog // ignore: cast_nullable_to_non_nullable + as DateTime?, )); } } @@ -209,13 +274,18 @@ class _$MapViewStateImpl implements _MapViewState { const _$MapViewStateImpl( {this.loading = false, this.fetchingInviteCode = false, + this.hasLocationEnabled = false, + this.hasLocationServiceEnabled = false, + this.hasNotificationEnabled = false, + this.hasFineLocationEnabled = false, final List userInfo = const [], final List places = const [], final List markers = const [], this.selectedUser, this.defaultPosition, this.spaceInvitationCode = '', - this.error}) + this.error, + this.showLocationDialog}) : _userInfo = userInfo, _places = places, _markers = markers; @@ -226,6 +296,18 @@ class _$MapViewStateImpl implements _MapViewState { @override @JsonKey() final bool fetchingInviteCode; + @override + @JsonKey() + final bool hasLocationEnabled; + @override + @JsonKey() + final bool hasLocationServiceEnabled; + @override + @JsonKey() + final bool hasNotificationEnabled; + @override + @JsonKey() + final bool hasFineLocationEnabled; final List _userInfo; @override @JsonKey() @@ -262,10 +344,12 @@ class _$MapViewStateImpl implements _MapViewState { final String spaceInvitationCode; @override final Object? error; + @override + final DateTime? showLocationDialog; @override String toString() { - return 'MapViewState(loading: $loading, fetchingInviteCode: $fetchingInviteCode, userInfo: $userInfo, places: $places, markers: $markers, selectedUser: $selectedUser, defaultPosition: $defaultPosition, spaceInvitationCode: $spaceInvitationCode, error: $error)'; + return 'MapViewState(loading: $loading, fetchingInviteCode: $fetchingInviteCode, hasLocationEnabled: $hasLocationEnabled, hasLocationServiceEnabled: $hasLocationServiceEnabled, hasNotificationEnabled: $hasNotificationEnabled, hasFineLocationEnabled: $hasFineLocationEnabled, userInfo: $userInfo, places: $places, markers: $markers, selectedUser: $selectedUser, defaultPosition: $defaultPosition, spaceInvitationCode: $spaceInvitationCode, error: $error, showLocationDialog: $showLocationDialog)'; } @override @@ -276,6 +360,15 @@ class _$MapViewStateImpl implements _MapViewState { const DeepCollectionEquality().equals(other.loading, loading) && (identical(other.fetchingInviteCode, fetchingInviteCode) || other.fetchingInviteCode == fetchingInviteCode) && + (identical(other.hasLocationEnabled, hasLocationEnabled) || + other.hasLocationEnabled == hasLocationEnabled) && + (identical(other.hasLocationServiceEnabled, + hasLocationServiceEnabled) || + other.hasLocationServiceEnabled == hasLocationServiceEnabled) && + (identical(other.hasNotificationEnabled, hasNotificationEnabled) || + other.hasNotificationEnabled == hasNotificationEnabled) && + (identical(other.hasFineLocationEnabled, hasFineLocationEnabled) || + other.hasFineLocationEnabled == hasFineLocationEnabled) && const DeepCollectionEquality().equals(other._userInfo, _userInfo) && const DeepCollectionEquality().equals(other._places, _places) && const DeepCollectionEquality().equals(other._markers, _markers) && @@ -285,7 +378,9 @@ class _$MapViewStateImpl implements _MapViewState { other.defaultPosition == defaultPosition) && (identical(other.spaceInvitationCode, spaceInvitationCode) || other.spaceInvitationCode == spaceInvitationCode) && - const DeepCollectionEquality().equals(other.error, error)); + const DeepCollectionEquality().equals(other.error, error) && + (identical(other.showLocationDialog, showLocationDialog) || + other.showLocationDialog == showLocationDialog)); } @override @@ -293,13 +388,18 @@ class _$MapViewStateImpl implements _MapViewState { runtimeType, const DeepCollectionEquality().hash(loading), fetchingInviteCode, + hasLocationEnabled, + hasLocationServiceEnabled, + hasNotificationEnabled, + hasFineLocationEnabled, const DeepCollectionEquality().hash(_userInfo), const DeepCollectionEquality().hash(_places), const DeepCollectionEquality().hash(_markers), selectedUser, defaultPosition, spaceInvitationCode, - const DeepCollectionEquality().hash(error)); + const DeepCollectionEquality().hash(error), + showLocationDialog); @JsonKey(ignore: true) @override @@ -312,19 +412,32 @@ abstract class _MapViewState implements MapViewState { const factory _MapViewState( {final dynamic loading, final bool fetchingInviteCode, + final bool hasLocationEnabled, + final bool hasLocationServiceEnabled, + final bool hasNotificationEnabled, + final bool hasFineLocationEnabled, final List userInfo, final List places, final List markers, final ApiUserInfo? selectedUser, final CameraPosition? defaultPosition, final String spaceInvitationCode, - final Object? error}) = _$MapViewStateImpl; + final Object? error, + final DateTime? showLocationDialog}) = _$MapViewStateImpl; @override dynamic get loading; @override bool get fetchingInviteCode; @override + bool get hasLocationEnabled; + @override + bool get hasLocationServiceEnabled; + @override + bool get hasNotificationEnabled; + @override + bool get hasFineLocationEnabled; + @override List get userInfo; @override List get places; @@ -339,6 +452,8 @@ abstract class _MapViewState implements MapViewState { @override Object? get error; @override + DateTime? get showLocationDialog; + @override @JsonKey(ignore: true) _$$MapViewStateImplCopyWith<_$MapViewStateImpl> get copyWith => throw _privateConstructorUsedError; From f60c2fe14460c54d5b6722fa0198e9e3f8931c6e Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 19 Jun 2024 18:01:25 +0530 Subject: [PATCH 12/65] Fix permanently denied permission --- data/lib/service/permission_service.dart | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/data/lib/service/permission_service.dart b/data/lib/service/permission_service.dart index 47293a84..ebacb605 100644 --- a/data/lib/service/permission_service.dart +++ b/data/lib/service/permission_service.dart @@ -54,12 +54,7 @@ class PermissionService { if (status.isDenied) { final newStatus = await permission.request(); - if (newStatus.isDenied || newStatus.isPermanentlyDenied) { - await openAppSettings(); - return false; - } else { - return newStatus.isGranted; - } + return newStatus.isGranted; } else if (status.isPermanentlyDenied) { await openAppSettings(); return false; From a59fb394e4646a2a38c1fa527eee3f590b85d768 Mon Sep 17 00:00:00 2001 From: kaushik Date: Thu, 20 Jun 2024 16:57:31 +0530 Subject: [PATCH 13/65] Implement places list screen. --- app/assets/images/ic_close_icon.svg | 5 + app/assets/images/ic_edit_profile.svg | 8 +- app/assets/images/ic_places_gym_icon.svg | 5 + app/assets/images/ic_places_home_icon.svg | 5 + app/assets/images/ic_places_library_icon.svg | 5 + app/assets/images/ic_places_park_icon.svg | 5 + app/assets/images/ic_places_school_icon.svg | 5 + app/assets/images/ic_places_work_icon.svg | 5 + app/assets/images/ic_plus_icon.svg | 5 + app/assets/locales/app_en.arb | 15 +- app/lib/gen/assets.gen.dart | 32 ++ app/lib/ui/app_route.dart | 24 +- .../geofence/places/places_list_view.dart | 299 ++++++++++++ .../places/places_list_view_model.dart | 91 ++++ .../places_list_view_model.freezed.dart | 461 ++++++++++++++++++ app/lib/ui/flow/home/map/map_view.dart | 5 +- app/lib/ui/flow/home/map/map_view_model.dart | 1 - data/lib/service/place_service.dart | 4 + 18 files changed, 968 insertions(+), 12 deletions(-) create mode 100644 app/assets/images/ic_close_icon.svg create mode 100644 app/assets/images/ic_places_gym_icon.svg create mode 100644 app/assets/images/ic_places_home_icon.svg create mode 100644 app/assets/images/ic_places_library_icon.svg create mode 100644 app/assets/images/ic_places_park_icon.svg create mode 100644 app/assets/images/ic_places_school_icon.svg create mode 100644 app/assets/images/ic_places_work_icon.svg create mode 100644 app/assets/images/ic_plus_icon.svg create mode 100644 app/lib/ui/flow/geofence/places/places_list_view.dart create mode 100644 app/lib/ui/flow/geofence/places/places_list_view_model.dart create mode 100644 app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart diff --git a/app/assets/images/ic_close_icon.svg b/app/assets/images/ic_close_icon.svg new file mode 100644 index 00000000..e626534f --- /dev/null +++ b/app/assets/images/ic_close_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/images/ic_edit_profile.svg b/app/assets/images/ic_edit_profile.svg index b965c959..edab7462 100644 --- a/app/assets/images/ic_edit_profile.svg +++ b/app/assets/images/ic_edit_profile.svg @@ -1,4 +1,8 @@ - - + + diff --git a/app/assets/images/ic_places_gym_icon.svg b/app/assets/images/ic_places_gym_icon.svg new file mode 100644 index 00000000..d6419b90 --- /dev/null +++ b/app/assets/images/ic_places_gym_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/images/ic_places_home_icon.svg b/app/assets/images/ic_places_home_icon.svg new file mode 100644 index 00000000..d8be84c1 --- /dev/null +++ b/app/assets/images/ic_places_home_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/images/ic_places_library_icon.svg b/app/assets/images/ic_places_library_icon.svg new file mode 100644 index 00000000..07b16ef7 --- /dev/null +++ b/app/assets/images/ic_places_library_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/images/ic_places_park_icon.svg b/app/assets/images/ic_places_park_icon.svg new file mode 100644 index 00000000..5cfde0de --- /dev/null +++ b/app/assets/images/ic_places_park_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/images/ic_places_school_icon.svg b/app/assets/images/ic_places_school_icon.svg new file mode 100644 index 00000000..5c799eb8 --- /dev/null +++ b/app/assets/images/ic_places_school_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/images/ic_places_work_icon.svg b/app/assets/images/ic_places_work_icon.svg new file mode 100644 index 00000000..362e0712 --- /dev/null +++ b/app/assets/images/ic_places_work_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/images/ic_plus_icon.svg b/app/assets/images/ic_plus_icon.svg new file mode 100644 index 00000000..05954d77 --- /dev/null +++ b/app/assets/images/ic_plus_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/locales/app_en.arb b/app/assets/locales/app_en.arb index a0c531b8..682f2827 100644 --- a/app/assets/locales/app_en.arb +++ b/app/assets/locales/app_en.arb @@ -141,5 +141,18 @@ "contact_support_description_title": "Description", "contact_support_attachment": "Attachment (if any)", "contact_support_submit_title": "Submit", - "contact_support_feedback_alert_message": "Thanks! Your feedback has been recorded." + "contact_support_feedback_alert_message": "Thanks! Your feedback has been recorded.", + + "@_PLACES": { + }, + "places_list_title": "Places", + "places_list_add_place_btn_text": "Add place", + "places_list_suggestion_add_your_place":"Add your {place}", + "places_list_suggestion_home_text": "Home", + "places_list_suggestion_work_text": "Work", + "places_list_suggestion_school_text": "School", + "places_list_suggestion_gym_text": "Gym", + "places_list_suggestion_library_text": "Library", + "places_list_suggestion_local_park_text": "Local park", + "places_list_delete_dialog_content_text": "Are you sure you want to delete this place? This action cannot be undone." } \ No newline at end of file diff --git a/app/lib/gen/assets.gen.dart b/app/lib/gen/assets.gen.dart index 994d2d88..738045c0 100644 --- a/app/lib/gen/assets.gen.dart +++ b/app/lib/gen/assets.gen.dart @@ -31,6 +31,9 @@ class $AssetsImagesGen { /// File path: assets/images/ic_add_user_icon.svg String get icAddUserIcon => 'assets/images/ic_add_user_icon.svg'; + /// File path: assets/images/ic_close_icon.svg + String get icCloseIcon => 'assets/images/ic_close_icon.svg'; + /// File path: assets/images/ic_contact_support.svg String get icContactSupport => 'assets/images/ic_contact_support.svg'; @@ -62,6 +65,27 @@ class $AssetsImagesGen { AssetGenImage get icPlaceMarkerIcon => const AssetGenImage('assets/images/ic_place_marker_icon.png'); + /// File path: assets/images/ic_places_gym_icon.svg + String get icPlacesGymIcon => 'assets/images/ic_places_gym_icon.svg'; + + /// File path: assets/images/ic_places_home_icon.svg + String get icPlacesHomeIcon => 'assets/images/ic_places_home_icon.svg'; + + /// File path: assets/images/ic_places_library_icon.svg + String get icPlacesLibraryIcon => 'assets/images/ic_places_library_icon.svg'; + + /// File path: assets/images/ic_places_park_icon.svg + String get icPlacesParkIcon => 'assets/images/ic_places_park_icon.svg'; + + /// File path: assets/images/ic_places_school_icon.svg + String get icPlacesSchoolIcon => 'assets/images/ic_places_school_icon.svg'; + + /// File path: assets/images/ic_places_work_icon.svg + String get icPlacesWorkIcon => 'assets/images/ic_places_work_icon.svg'; + + /// File path: assets/images/ic_plus_icon.svg + String get icPlusIcon => 'assets/images/ic_plus_icon.svg'; + /// File path: assets/images/ic_privacy_policy.svg String get icPrivacyPolicy => 'assets/images/ic_privacy_policy.svg'; @@ -102,6 +126,7 @@ class $AssetsImagesGen { icAboutUs, icAddMember, icAddUserIcon, + icCloseIcon, icContactSupport, icDownArrowIcon, icEditProfile, @@ -112,6 +137,13 @@ class $AssetsImagesGen { icLocation, icMessage, icPlaceMarkerIcon, + icPlacesGymIcon, + icPlacesHomeIcon, + icPlacesLibraryIcon, + icPlacesParkIcon, + icPlacesSchoolIcon, + icPlacesWorkIcon, + icPlusIcon, icPrivacyPolicy, icRelocateIcon, icRemove, diff --git a/app/lib/ui/app_route.dart b/app/lib/ui/app_route.dart index 4b8e2f17..49e951ee 100644 --- a/app/lib/ui/app_route.dart +++ b/app/lib/ui/app_route.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:go_router/go_router.dart'; import 'package:yourspace_flutter/ui/flow/auth/sign_in/phone/verification/phone_verification_screen.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_view.dart'; import 'package:yourspace_flutter/ui/flow/onboard/pick_name_screen.dart'; import 'package:yourspace_flutter/ui/flow/setting/contact_support/contact_support_screen.dart'; import 'package:yourspace_flutter/ui/flow/setting/profile/profile_screen.dart'; @@ -24,6 +25,7 @@ class AppRoute { static const pathProfile = '/profile'; static const pathEditSpace = '/space'; static const pathContactSupport = '/contact-support'; + static const pathPlacesList = '/places-list'; final String path; final String? name; @@ -110,7 +112,7 @@ class AppRoute { ); static AppRoute get pickName => AppRoute( - "/pick-name", + "/pick-name", builder: (_) => const PickNameScreen(), ); @@ -126,10 +128,10 @@ class AppRoute { AppRoute(pathCreateSpace, builder: (_) => const CreateSpace()); static AppRoute get joinSpace => - AppRoute(pathJoinSpace, builder: (_) => const JoinSpace()); + AppRoute(pathJoinSpace, builder: (_) => const JoinSpace()); - static AppRoute inviteCode({ - required String code, required String spaceName}) { + static AppRoute inviteCode( + {required String code, required String spaceName}) { return AppRoute( pathInviteCode, builder: (_) => InviteCode(spaceName: spaceName, inviteCode: code), @@ -149,8 +151,13 @@ class AppRoute { ); } - static AppRoute get contactSupport => - AppRoute(pathContactSupport, builder: (_) => const ContactSupportScreen()); + static AppRoute get contactSupport => AppRoute(pathContactSupport, + builder: (_) => const ContactSupportScreen()); + + static AppRoute placesList(String spaceId) { + return AppRoute(pathPlacesList, + builder: (_) => PlacesListView(spaceId: spaceId)); + } static final routes = [ GoRoute( @@ -191,7 +198,6 @@ class AppRoute { ? const PhoneVerificationScreen('', '') : state.widget(context); }), - GoRoute( path: pathCreateSpace, builder: (context, state) => state.widget(context), @@ -220,6 +226,10 @@ class AppRoute { path: pathContactSupport, builder: (context, state) => state.widget(context), ), + GoRoute( + path: pathPlacesList, + builder: (context, state) => state.widget(context), + ) ]; } diff --git a/app/lib/ui/flow/geofence/places/places_list_view.dart b/app/lib/ui/flow/geofence/places/places_list_view.dart new file mode 100644 index 00000000..f2e8e988 --- /dev/null +++ b/app/lib/ui/flow/geofence/places/places_list_view.dart @@ -0,0 +1,299 @@ +import 'package:data/api/place/api_place.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:style/animation/on_tap_scale.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/indicator/progress_indicator.dart'; +import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; +import 'package:yourspace_flutter/ui/components/app_page.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_view_model.dart'; + +import '../../../../domain/extenstions/widget_extensions.dart'; +import '../../../../gen/assets.gen.dart'; + +class PlacesListView extends ConsumerStatefulWidget { + final String spaceId; + + const PlacesListView({super.key, required this.spaceId}); + + @override + ConsumerState createState() => _PlacesViewState(); +} + +class _PlacesViewState extends ConsumerState { + late PlacesListViewNotifier notifier; + List suggestions = []; + + @override + void initState() { + super.initState(); + runPostFrame(() { + notifier = ref.watch(placesListViewStateProvider.notifier); + notifier.loadPlaces(widget.spaceId); + }); + } + + @override + Widget build(BuildContext context) { + final state = ref.watch(placesListViewStateProvider); + + _observeShowDeletePlaceDialog(); + _observeCurrentUserPlaces(state); + + return AppPage(title: context.l10n.places_list_title, body: _body(state)); + } + + Widget _body(PlacesListState state) { + if (state.loading) { + return const Center( + child: AppProgressIndicator(), + ); + } + final placeLength = (state.places.isEmpty) ? 0 : state.places.length + 1; + return Column( + children: [ + Expanded( + child: ListView.builder( + itemCount: placeLength + suggestions.length, + itemBuilder: (_, index) { + if (index < state.places.length) { + return _placesListItem(state, state.places[index]); + } + + if (index == state.places.length && state.places.isNotEmpty) { + return Padding( + padding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Divider(color: context.colorScheme.outline, height: 1), + ); + } + + final placeIndex = (state.places.isEmpty) + ? index + : index - state.places.length - 1; + + final item = suggestions[placeIndex]; + return _placeItemView( + placeName: + context.l10n.places_list_suggestion_add_your_place(item), + icon: _getPlacesIcon(item), + isSuggestion: true, + onDeletePlace: () {}, + ); + }, + ), + ), + Align(alignment: Alignment.bottomRight, child: _addPlaceButton()) + ], + ); + } + + Widget _addPlaceButton() { + return Container( + margin: EdgeInsets.only( + right: 16, + bottom: context.mediaQueryPadding.bottom + 16, + ), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: context.colorScheme.primary, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SvgPicture.asset( + Assets.images.icPlusIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.onPrimary, + BlendMode.srcATop, + ), + ), + const SizedBox(width: 8), + Text( + context.l10n.places_list_add_place_btn_text, + style: AppTextStyle.button.copyWith( + color: context.colorScheme.onPrimary, + ), + ) + ], + ), + ); + } + + Widget _placesListItem(PlacesListState state, ApiPlace item) { + final icon = _getPlacesIcon(item.name); + final isDeleting = + state.deletingPlaces && state.placesToDelete?.id == item.id; + final allowDelete = state.currentUser?.id == item.created_by; + return _placeItemView( + placeName: item.name, + icon: icon, + allowDelete: allowDelete, + isDeleting: isDeleting, + onDeletePlace: () { + notifier.onClickDeletePlace(item); + }, + ); + } + + Widget _placeItemView({ + required String placeName, + required String icon, + bool isSuggestion = false, + bool allowDelete = false, + bool isDeleting = false, + required VoidCallback onDeletePlace, + }) { + final enabled = !isSuggestion && allowDelete; + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + height: 36, + width: 36, + decoration: BoxDecoration( + color: context.colorScheme.containerLowOnSurface, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: SvgPicture.asset( + icon, + colorFilter: ColorFilter.mode( + context.colorScheme.textPrimary, + BlendMode.srcATop, + ), + ), + ), + ), + const SizedBox(width: 16), + Expanded( + child: Text( + placeName, + style: AppTextStyle.subtitle3 + .copyWith(color: context.colorScheme.textPrimary), + overflow: TextOverflow.ellipsis, + ), + ), + (isDeleting) + ? const AppProgressIndicator(size: AppProgressIndicatorSize.small) + : Visibility( + visible: enabled, + child: OnTapScale( + onTap: onDeletePlace, + child: SvgPicture.asset( + Assets.images.icCloseIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.textPrimary, + BlendMode.srcATop, + ), + ), + ), + ), + ], + ), + ); + } + + void _observeCurrentUserPlaces(PlacesListState state) { + ref.listen(placesListViewStateProvider.select((state) => state.places), + (_, next) { + if (next.isNotEmpty) { + final suggestedPlaces = _getSuggestionsPlaces(); + + final newSuggestedPlace = suggestedPlaces.where((suggestion) { + final suggestionName = suggestion.toLowerCase(); + + for (final place in next) { + final placeName = place.name.toLowerCase(); + if (state.currentUser?.id == place.created_by && + suggestionName == placeName) { + return false; + } + } + return true; + }).toList(); + + setState(() { + suggestions = newSuggestedPlace; + }); + } + }); + } + + List _getSuggestionsPlaces() { + return [ + context.l10n.places_list_suggestion_home_text, + context.l10n.places_list_suggestion_work_text, + context.l10n.places_list_suggestion_school_text, + context.l10n.places_list_suggestion_gym_text, + context.l10n.places_list_suggestion_library_text, + context.l10n.places_list_suggestion_local_park_text, + ]; + } + + String _getPlacesIcon(String name) { + if (name == 'Home') { + return Assets.images.icPlacesHomeIcon; + } else if (name == 'Work') { + return Assets.images.icPlacesWorkIcon; + } else if (name == 'School') { + return Assets.images.icPlacesSchoolIcon; + } else if (name == 'Gym') { + return Assets.images.icPlacesGymIcon; + } else if (name == 'Library') { + return Assets.images.icPlacesLibraryIcon; + } else if (name == 'Local park') { + return Assets.images.icPlacesParkIcon; + } else { + return Assets.images.icLocation; + } + } + + void _observeShowDeletePlaceDialog() { + ref.listen( + placesListViewStateProvider + .select((state) => state.showDeletePlaceDialog), (_, next) { + if (next != null) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + content: Text( + context.l10n.places_list_delete_dialog_content_text, + ), + actions: [ + TextButton( + child: Text( + context.l10n.common_cancel, + style: AppTextStyle.button + .copyWith(color: context.colorScheme.textSecondary), + ), + onPressed: () { + notifier.dismissDeletePlaceDialog(); + Navigator.of(context).pop(); + }, + ), + TextButton( + child: Text( + context.l10n.common_delete, + style: AppTextStyle.button + .copyWith(color: context.colorScheme.alert), + ), + onPressed: () { + notifier.deletePlace(); + Navigator.of(context).pop(); + }, + ), + ], + ); + }); + } + }); + } +} diff --git a/app/lib/ui/flow/geofence/places/places_list_view_model.dart b/app/lib/ui/flow/geofence/places/places_list_view_model.dart new file mode 100644 index 00000000..ff3f8b0a --- /dev/null +++ b/app/lib/ui/flow/geofence/places/places_list_view_model.dart @@ -0,0 +1,91 @@ +import 'package:data/api/auth/auth_models.dart'; +import 'package:data/api/place/api_place.dart'; +import 'package:data/log/logger.dart'; +import 'package:data/service/place_service.dart'; +import 'package:data/storage/app_preferences.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'places_list_view_model.freezed.dart'; + +final placesListViewStateProvider = + StateNotifierProvider.autoDispose( + (ref) { + return PlacesListViewNotifier( + ref.read(currentUserPod), + ref.read(placeServiceProvider), + ); +}); + +class PlacesListViewNotifier extends StateNotifier { + final PlaceService placeService; + + PlacesListViewNotifier(currentUser, this.placeService) + : super(PlacesListState(currentUser: currentUser)); + + void loadPlaces(String spaceId) async { + if (state.loading) return; + try { + state = state.copyWith(loading: true, spaceId: spaceId); + placeService.getAllPlacesStream(spaceId).listen((places) { + state = state.copyWith(places: places, loading: false); + }); + } catch (error, stack) { + state = state.copyWith(loading: false, error: error); + logger.e( + 'PlacesListViewNotifier: Error while getting All places', + error: error, + stackTrace: stack, + ); + } + } + + void onClickDeletePlace(ApiPlace place) { + state = state.copyWith( + placesToDelete: place, + showDeletePlaceDialog: DateTime.now(), + ); + } + + void dismissDeletePlaceDialog() { + state = state.copyWith(deletingPlaces: false, placesToDelete: null); + } + + void deletePlace() async { + try { + state = state.copyWith(deletingPlaces: true); + final place = state.placesToDelete; + await placeService.deletePlace(state.spaceId!, place!.id); + state = state.copyWith(deletingPlaces: false); + } catch (error, stack) { + state = state.copyWith(deletingPlaces: false); + logger.e( + 'PlaceListNotifier: Error while deleting place', + error: error, + stackTrace: stack, + ); + } + } +} + +@freezed +class PlacesListState with _$PlacesListState { + const factory PlacesListState({ + @Default(false) bool loading, + @Default(false) bool deletingPlaces, + String? spaceId, + DateTime? showDeletePlaceDialog, + ApiPlace? placesToDelete, + ApiUser? currentUser, + @Default([]) List places, + Object? error, + }) = _PlacesListState; +} + +@freezed +class Suggestions with _$Suggestions { + const factory Suggestions({ + required String name, + required String icon, + }) = _Suggestions; +} diff --git a/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart b/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart new file mode 100644 index 00000000..52110eb1 --- /dev/null +++ b/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart @@ -0,0 +1,461 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'places_list_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$PlacesListState { + bool get loading => throw _privateConstructorUsedError; + bool get deletingPlaces => throw _privateConstructorUsedError; + String? get spaceId => throw _privateConstructorUsedError; + DateTime? get showDeletePlaceDialog => throw _privateConstructorUsedError; + ApiPlace? get placesToDelete => throw _privateConstructorUsedError; + ApiUser? get currentUser => throw _privateConstructorUsedError; + List get places => throw _privateConstructorUsedError; + Object? get error => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $PlacesListStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PlacesListStateCopyWith<$Res> { + factory $PlacesListStateCopyWith( + PlacesListState value, $Res Function(PlacesListState) then) = + _$PlacesListStateCopyWithImpl<$Res, PlacesListState>; + @useResult + $Res call( + {bool loading, + bool deletingPlaces, + String? spaceId, + DateTime? showDeletePlaceDialog, + ApiPlace? placesToDelete, + ApiUser? currentUser, + List places, + Object? error}); + + $ApiPlaceCopyWith<$Res>? get placesToDelete; + $ApiUserCopyWith<$Res>? get currentUser; +} + +/// @nodoc +class _$PlacesListStateCopyWithImpl<$Res, $Val extends PlacesListState> + implements $PlacesListStateCopyWith<$Res> { + _$PlacesListStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = null, + Object? deletingPlaces = null, + Object? spaceId = freezed, + Object? showDeletePlaceDialog = freezed, + Object? placesToDelete = freezed, + Object? currentUser = freezed, + Object? places = null, + Object? error = freezed, + }) { + return _then(_value.copyWith( + loading: null == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as bool, + deletingPlaces: null == deletingPlaces + ? _value.deletingPlaces + : deletingPlaces // ignore: cast_nullable_to_non_nullable + as bool, + spaceId: freezed == spaceId + ? _value.spaceId + : spaceId // ignore: cast_nullable_to_non_nullable + as String?, + showDeletePlaceDialog: freezed == showDeletePlaceDialog + ? _value.showDeletePlaceDialog + : showDeletePlaceDialog // ignore: cast_nullable_to_non_nullable + as DateTime?, + placesToDelete: freezed == placesToDelete + ? _value.placesToDelete + : placesToDelete // ignore: cast_nullable_to_non_nullable + as ApiPlace?, + currentUser: freezed == currentUser + ? _value.currentUser + : currentUser // ignore: cast_nullable_to_non_nullable + as ApiUser?, + places: null == places + ? _value.places + : places // ignore: cast_nullable_to_non_nullable + as List, + error: freezed == error ? _value.error : error, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ApiPlaceCopyWith<$Res>? get placesToDelete { + if (_value.placesToDelete == null) { + return null; + } + + return $ApiPlaceCopyWith<$Res>(_value.placesToDelete!, (value) { + return _then(_value.copyWith(placesToDelete: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $ApiUserCopyWith<$Res>? get currentUser { + if (_value.currentUser == null) { + return null; + } + + return $ApiUserCopyWith<$Res>(_value.currentUser!, (value) { + return _then(_value.copyWith(currentUser: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$PlacesListStateImplCopyWith<$Res> + implements $PlacesListStateCopyWith<$Res> { + factory _$$PlacesListStateImplCopyWith(_$PlacesListStateImpl value, + $Res Function(_$PlacesListStateImpl) then) = + __$$PlacesListStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {bool loading, + bool deletingPlaces, + String? spaceId, + DateTime? showDeletePlaceDialog, + ApiPlace? placesToDelete, + ApiUser? currentUser, + List places, + Object? error}); + + @override + $ApiPlaceCopyWith<$Res>? get placesToDelete; + @override + $ApiUserCopyWith<$Res>? get currentUser; +} + +/// @nodoc +class __$$PlacesListStateImplCopyWithImpl<$Res> + extends _$PlacesListStateCopyWithImpl<$Res, _$PlacesListStateImpl> + implements _$$PlacesListStateImplCopyWith<$Res> { + __$$PlacesListStateImplCopyWithImpl( + _$PlacesListStateImpl _value, $Res Function(_$PlacesListStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = null, + Object? deletingPlaces = null, + Object? spaceId = freezed, + Object? showDeletePlaceDialog = freezed, + Object? placesToDelete = freezed, + Object? currentUser = freezed, + Object? places = null, + Object? error = freezed, + }) { + return _then(_$PlacesListStateImpl( + loading: null == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as bool, + deletingPlaces: null == deletingPlaces + ? _value.deletingPlaces + : deletingPlaces // ignore: cast_nullable_to_non_nullable + as bool, + spaceId: freezed == spaceId + ? _value.spaceId + : spaceId // ignore: cast_nullable_to_non_nullable + as String?, + showDeletePlaceDialog: freezed == showDeletePlaceDialog + ? _value.showDeletePlaceDialog + : showDeletePlaceDialog // ignore: cast_nullable_to_non_nullable + as DateTime?, + placesToDelete: freezed == placesToDelete + ? _value.placesToDelete + : placesToDelete // ignore: cast_nullable_to_non_nullable + as ApiPlace?, + currentUser: freezed == currentUser + ? _value.currentUser + : currentUser // ignore: cast_nullable_to_non_nullable + as ApiUser?, + places: null == places + ? _value._places + : places // ignore: cast_nullable_to_non_nullable + as List, + error: freezed == error ? _value.error : error, + )); + } +} + +/// @nodoc + +class _$PlacesListStateImpl implements _PlacesListState { + const _$PlacesListStateImpl( + {this.loading = false, + this.deletingPlaces = false, + this.spaceId, + this.showDeletePlaceDialog, + this.placesToDelete, + this.currentUser, + final List places = const [], + this.error}) + : _places = places; + + @override + @JsonKey() + final bool loading; + @override + @JsonKey() + final bool deletingPlaces; + @override + final String? spaceId; + @override + final DateTime? showDeletePlaceDialog; + @override + final ApiPlace? placesToDelete; + @override + final ApiUser? currentUser; + final List _places; + @override + @JsonKey() + List get places { + if (_places is EqualUnmodifiableListView) return _places; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_places); + } + + @override + final Object? error; + + @override + String toString() { + return 'PlacesListState(loading: $loading, deletingPlaces: $deletingPlaces, spaceId: $spaceId, showDeletePlaceDialog: $showDeletePlaceDialog, placesToDelete: $placesToDelete, currentUser: $currentUser, places: $places, error: $error)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PlacesListStateImpl && + (identical(other.loading, loading) || other.loading == loading) && + (identical(other.deletingPlaces, deletingPlaces) || + other.deletingPlaces == deletingPlaces) && + (identical(other.spaceId, spaceId) || other.spaceId == spaceId) && + (identical(other.showDeletePlaceDialog, showDeletePlaceDialog) || + other.showDeletePlaceDialog == showDeletePlaceDialog) && + (identical(other.placesToDelete, placesToDelete) || + other.placesToDelete == placesToDelete) && + (identical(other.currentUser, currentUser) || + other.currentUser == currentUser) && + const DeepCollectionEquality().equals(other._places, _places) && + const DeepCollectionEquality().equals(other.error, error)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + loading, + deletingPlaces, + spaceId, + showDeletePlaceDialog, + placesToDelete, + currentUser, + const DeepCollectionEquality().hash(_places), + const DeepCollectionEquality().hash(error)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PlacesListStateImplCopyWith<_$PlacesListStateImpl> get copyWith => + __$$PlacesListStateImplCopyWithImpl<_$PlacesListStateImpl>( + this, _$identity); +} + +abstract class _PlacesListState implements PlacesListState { + const factory _PlacesListState( + {final bool loading, + final bool deletingPlaces, + final String? spaceId, + final DateTime? showDeletePlaceDialog, + final ApiPlace? placesToDelete, + final ApiUser? currentUser, + final List places, + final Object? error}) = _$PlacesListStateImpl; + + @override + bool get loading; + @override + bool get deletingPlaces; + @override + String? get spaceId; + @override + DateTime? get showDeletePlaceDialog; + @override + ApiPlace? get placesToDelete; + @override + ApiUser? get currentUser; + @override + List get places; + @override + Object? get error; + @override + @JsonKey(ignore: true) + _$$PlacesListStateImplCopyWith<_$PlacesListStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$Suggestions { + String get name => throw _privateConstructorUsedError; + String get icon => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $SuggestionsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SuggestionsCopyWith<$Res> { + factory $SuggestionsCopyWith( + Suggestions value, $Res Function(Suggestions) then) = + _$SuggestionsCopyWithImpl<$Res, Suggestions>; + @useResult + $Res call({String name, String icon}); +} + +/// @nodoc +class _$SuggestionsCopyWithImpl<$Res, $Val extends Suggestions> + implements $SuggestionsCopyWith<$Res> { + _$SuggestionsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? icon = null, + }) { + return _then(_value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + icon: null == icon + ? _value.icon + : icon // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SuggestionsImplCopyWith<$Res> + implements $SuggestionsCopyWith<$Res> { + factory _$$SuggestionsImplCopyWith( + _$SuggestionsImpl value, $Res Function(_$SuggestionsImpl) then) = + __$$SuggestionsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String name, String icon}); +} + +/// @nodoc +class __$$SuggestionsImplCopyWithImpl<$Res> + extends _$SuggestionsCopyWithImpl<$Res, _$SuggestionsImpl> + implements _$$SuggestionsImplCopyWith<$Res> { + __$$SuggestionsImplCopyWithImpl( + _$SuggestionsImpl _value, $Res Function(_$SuggestionsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? icon = null, + }) { + return _then(_$SuggestionsImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + icon: null == icon + ? _value.icon + : icon // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$SuggestionsImpl implements _Suggestions { + const _$SuggestionsImpl({required this.name, required this.icon}); + + @override + final String name; + @override + final String icon; + + @override + String toString() { + return 'Suggestions(name: $name, icon: $icon)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SuggestionsImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.icon, icon) || other.icon == icon)); + } + + @override + int get hashCode => Object.hash(runtimeType, name, icon); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SuggestionsImplCopyWith<_$SuggestionsImpl> get copyWith => + __$$SuggestionsImplCopyWithImpl<_$SuggestionsImpl>(this, _$identity); +} + +abstract class _Suggestions implements Suggestions { + const factory _Suggestions( + {required final String name, + required final String icon}) = _$SuggestionsImpl; + + @override + String get name; + @override + String get icon; + @override + @JsonKey(ignore: true) + _$$SuggestionsImplCopyWith<_$SuggestionsImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index 108afafc..de57da19 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -89,7 +89,10 @@ class _MapScreenState extends ConsumerState { notifier.showMemberDetail(member); }, onRelocateTap: () {}, - onPlacesTap: () {}, + onPlacesTap: () { + if (widget.space == null) return; + AppRoute.placesList(widget.space!.space.id).push(context); + }, onDismiss: () => notifier.onDismissMemberDetail(), onTapTimeline: () {}, ), diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index fdc7af4c..fea801af 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -68,7 +68,6 @@ class MapViewNotifier extends StateNotifier { error: error, stackTrace: stack, ); - state = state.copyWith(loading: false); } } diff --git a/data/lib/service/place_service.dart b/data/lib/service/place_service.dart index 474ef3c4..2a4d1355 100644 --- a/data/lib/service/place_service.dart +++ b/data/lib/service/place_service.dart @@ -25,4 +25,8 @@ class PlaceService { .map((doc) => ApiPlace.fromJson(doc.data() as Map)) .toList()); } + + Future deletePlace(String spaceId, String placeId) async { + await spacePlacesRef(spaceId).doc(placeId).delete(); + } } From b74b5a94989199eaf8ce1f11d259066dbcc45c74 Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 21 Jun 2024 15:29:45 +0530 Subject: [PATCH 14/65] Minor --- app/ios/Runner/AppDelegate.swift | 6 - app/lib/ui/app_route.dart | 13 ++ .../geofence/addplace/add_new_place_view.dart | 134 ++++++++++++++++++ .../addplace/add_new_place_view_model.dart | 51 +++++++ .../geofence/places/places_list_view.dart | 60 ++++---- app/lib/ui/flow/home/map/map_view_model.dart | 1 + data/.flutter-plugins | 50 +++---- data/.flutter-plugins-dependencies | 2 +- data/lib/service/place_service.dart | 17 +++ data/pubspec.yaml | 1 + 10 files changed, 276 insertions(+), 59 deletions(-) create mode 100644 app/lib/ui/flow/geofence/addplace/add_new_place_view.dart create mode 100644 app/lib/ui/flow/geofence/addplace/add_new_place_view_model.dart diff --git a/app/ios/Runner/AppDelegate.swift b/app/ios/Runner/AppDelegate.swift index fb55820e..70693e4a 100644 --- a/app/ios/Runner/AppDelegate.swift +++ b/app/ios/Runner/AppDelegate.swift @@ -7,13 +7,7 @@ import Flutter _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { -// GMSServices.provideAPIKey(getMapKey()) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } - -// func getMapKey() -> String { -// let mapApiKey = Bundle.main.object(forInfoDictionaryKey: "MapApiKey") as? String -// return mapApiKey ?? "" -// } } diff --git a/app/lib/ui/app_route.dart b/app/lib/ui/app_route.dart index 49e951ee..7aa64fba 100644 --- a/app/lib/ui/app_route.dart +++ b/app/lib/ui/app_route.dart @@ -13,6 +13,7 @@ import 'package:yourspace_flutter/ui/flow/space/join/join_space_screen.dart'; import 'flow/auth/sign_in/phone/sign_in_with_phone_screen.dart'; import 'flow/auth/sign_in/sign_in_method_screen.dart'; +import 'flow/geofence/addplace/add_new_place_view.dart'; import 'flow/home/home_screen.dart'; import 'flow/intro/intro_screen.dart'; @@ -26,6 +27,7 @@ class AppRoute { static const pathEditSpace = '/space'; static const pathContactSupport = '/contact-support'; static const pathPlacesList = '/places-list'; + static const pathAddNewPlace = '/add_new_place'; final String path; final String? name; @@ -159,6 +161,13 @@ class AppRoute { builder: (_) => PlacesListView(spaceId: spaceId)); } + static AppRoute addNewPlace(String spaceId) { + return AppRoute( + pathAddNewPlace, + builder: (_) => AddNewPlaceView(spaceId: spaceId), + ); + } + static final routes = [ GoRoute( path: intro.path, @@ -229,6 +238,10 @@ class AppRoute { GoRoute( path: pathPlacesList, builder: (context, state) => state.widget(context), + ), + GoRoute( + path: pathAddNewPlace, + builder: (context, state) => state.widget(context), ) ]; } diff --git a/app/lib/ui/flow/geofence/addplace/add_new_place_view.dart b/app/lib/ui/flow/geofence/addplace/add_new_place_view.dart new file mode 100644 index 00000000..c76a731a --- /dev/null +++ b/app/lib/ui/flow/geofence/addplace/add_new_place_view.dart @@ -0,0 +1,134 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/ui/components/app_page.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/addplace/add_new_place_view_model.dart'; + +import '../../../../gen/assets.gen.dart'; + +class AddNewPlaceView extends ConsumerStatefulWidget { + final String spaceId; + + const AddNewPlaceView({super.key, required this.spaceId}); + + @override + ConsumerState createState() => _AddNewPlaceViewState(); +} + +class _AddNewPlaceViewState extends ConsumerState { + late AddNewPlaceViewNotifier notifier; + + + @override + Widget build(BuildContext context) { + notifier = ref.watch(addNewPLaceStateProvider.notifier); + + return AppPage( + title: "Add a new place", + body: _body(), + ); + } + + Widget _body() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _searchTextField(), + const SizedBox(height: 56), + _locateOnMapView(), + const SizedBox(height: 40), + Text( + "Some suggestions...", + style: AppTextStyle.caption.copyWith( + color: context.colorScheme.textDisabled, + ), + ), + _placeSuggestionView() + ], + ), + ); + } + + Widget _searchTextField() { + return Column( + children: [ + TextField( + style: AppTextStyle.subtitle3, + onChanged: (value) { + notifier.onPlaceNameChanged(value.trim()); + }, + decoration: InputDecoration( + prefixIcon: Padding( + padding: const EdgeInsets.only(right: 8), + child: Icon( + Icons.search, + color: context.colorScheme.textDisabled, + ), + ), + hintText: 'Search address and location name', + hintStyle: AppTextStyle.subtitle3.copyWith( + color: context.colorScheme.textDisabled, + ), + contentPadding: const EdgeInsets.symmetric(vertical: 0), + prefixIconConstraints: const BoxConstraints( + minHeight: 0, + minWidth: 0, + ), + border: UnderlineInputBorder( + borderSide: BorderSide( + color: context.colorScheme.textDisabled, + ), + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: context.colorScheme.primary, + ), + ), + ), + ), + ], + ); + } + + Widget _locateOnMapView() { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: context.colorScheme.containerNormal, + ), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: context.colorScheme.containerLow), + child: SvgPicture.asset( + Assets.images.icLocation, + colorFilter: ColorFilter.mode( + context.colorScheme.textPrimary, + BlendMode.srcATop, + ), + ), + ), + const SizedBox(width: 16), + Text( + "Locate on map", + style: AppTextStyle.subtitle3.copyWith( + color: context.colorScheme.textPrimary, + ), + ) + ], + ), + ); + } + + Widget _placeSuggestionView() { + return Container(); + } +} diff --git a/app/lib/ui/flow/geofence/addplace/add_new_place_view_model.dart b/app/lib/ui/flow/geofence/addplace/add_new_place_view_model.dart new file mode 100644 index 00000000..50a05c4f --- /dev/null +++ b/app/lib/ui/flow/geofence/addplace/add_new_place_view_model.dart @@ -0,0 +1,51 @@ +import 'dart:async'; + +import 'package:data/log/logger.dart'; +import 'package:data/service/place_service.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'add_new_place_view_model.freezed.dart'; + +final addNewPLaceStateProvider = StateNotifierProvider.autoDispose< + AddNewPlaceViewNotifier, AddNewPlaceState>((ref) { + return AddNewPlaceViewNotifier(ref.read(placeServiceProvider)); +}); + +class AddNewPlaceViewNotifier extends StateNotifier { + final PlaceService placeService; + + AddNewPlaceViewNotifier(this.placeService) : super(const AddNewPlaceState()); + + Timer? _debounce; + + void onPlaceNameChanged(String value) { + if (_debounce?.isActive ?? false) _debounce!.cancel(); + + _debounce = Timer(const Duration(milliseconds: 500), () { + fidePlace(value); + }); + } + + void fidePlace(String value) async { + try { + state = state.copyWith(loading: true); + await placeService.findPlace(value,0.0,0.0); + } catch (error, stack) { + state = state.copyWith(error: error, loading: false); + logger.e( + 'PlaceListNotifier: Error while deleting place', + error: error, + stackTrace: stack, + ); + } + } +} + +@freezed +class AddNewPlaceState with _$AddNewPlaceState { + const factory AddNewPlaceState({ + @Default(false) loading, + Object? error, + }) = _AddNewPlaceState; +} diff --git a/app/lib/ui/flow/geofence/places/places_list_view.dart b/app/lib/ui/flow/geofence/places/places_list_view.dart index f2e8e988..e1ac79f1 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view.dart @@ -7,6 +7,7 @@ import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/indicator/progress_indicator.dart'; import 'package:style/text/app_text_dart.dart'; import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; +import 'package:yourspace_flutter/ui/app_route.dart'; import 'package:yourspace_flutter/ui/components/app_page.dart'; import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_view_model.dart'; @@ -91,34 +92,39 @@ class _PlacesViewState extends ConsumerState { } Widget _addPlaceButton() { - return Container( - margin: EdgeInsets.only( - right: 16, - bottom: context.mediaQueryPadding.bottom + 16, - ), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(30), - color: context.colorScheme.primary, - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - SvgPicture.asset( - Assets.images.icPlusIcon, - colorFilter: ColorFilter.mode( - context.colorScheme.onPrimary, - BlendMode.srcATop, - ), - ), - const SizedBox(width: 8), - Text( - context.l10n.places_list_add_place_btn_text, - style: AppTextStyle.button.copyWith( - color: context.colorScheme.onPrimary, + return OnTapScale( + onTap: () { + AppRoute.addNewPlace(widget.spaceId).push(context); + }, + child: Container( + margin: EdgeInsets.only( + right: 16, + bottom: context.mediaQueryPadding.bottom + 16, + ), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: context.colorScheme.primary, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SvgPicture.asset( + Assets.images.icPlusIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.onPrimary, + BlendMode.srcATop, + ), ), - ) - ], + const SizedBox(width: 8), + Text( + context.l10n.places_list_add_place_btn_text, + style: AppTextStyle.button.copyWith( + color: context.colorScheme.onPrimary, + ), + ) + ], + ), ), ); } diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index fea801af..dbce145a 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -170,6 +170,7 @@ class MapViewNotifier extends StateNotifier { } void showMemberDetail(ApiUserInfo member) { + print('XXX user:${member.location}'); final selectedMember = (state.selectedUser?.user.id == member.user.id) ? null : member; final position = (selectedMember != null && selectedMember.location != null) diff --git a/data/.flutter-plugins b/data/.flutter-plugins index ce4daee3..fbbdb450 100644 --- a/data/.flutter-plugins +++ b/data/.flutter-plugins @@ -1,26 +1,26 @@ # This is a generated file; do not edit or check into version control. -cloud_firestore=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/ -cloud_firestore_web=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/ -cloud_functions=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/ -cloud_functions_web=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/ -device_info_plus=/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/ -firebase_auth=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/ -firebase_auth_web=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/ -firebase_core=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/ -firebase_core_web=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/ -firebase_storage=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/ -firebase_storage_web=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/ -flutter_timezone=/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/ -google_sign_in=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in-6.2.1/ -google_sign_in_android=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.23/ -google_sign_in_ios=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/ -google_sign_in_web=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+3/ -package_info_plus=/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/ -path_provider_linux=/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ -path_provider_windows=/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ -shared_preferences=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/ -shared_preferences_android=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/ -shared_preferences_foundation=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/ -shared_preferences_linux=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/ -shared_preferences_web=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/ -shared_preferences_windows=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/ +cloud_firestore=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/ +cloud_firestore_web=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/ +cloud_functions=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/ +cloud_functions_web=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/ +device_info_plus=/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/ +firebase_auth=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/ +firebase_auth_web=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/ +firebase_core=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/ +firebase_core_web=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/ +firebase_storage=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/ +firebase_storage_web=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/ +flutter_timezone=/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/ +google_sign_in=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in-6.2.1/ +google_sign_in_android=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/ +google_sign_in_ios=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/ +google_sign_in_web=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/ +package_info_plus=/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/ +path_provider_linux=/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ +path_provider_windows=/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ +shared_preferences=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/ +shared_preferences_android=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/ +shared_preferences_foundation=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/ +shared_preferences_linux=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/ +shared_preferences_web=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/ +shared_preferences_windows=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/ diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index 0d340917..28fb68fa 100644 --- a/data/.flutter-plugins-dependencies +++ b/data/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.23/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"google_sign_in_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+3/","dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-06-06 12:12:52.852133","version":"3.22.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"google_sign_in_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/","dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-06-21 15:25:16.066666","version":"3.22.0"} \ No newline at end of file diff --git a/data/lib/service/place_service.dart b/data/lib/service/place_service.dart index 2a4d1355..9d087095 100644 --- a/data/lib/service/place_service.dart +++ b/data/lib/service/place_service.dart @@ -1,9 +1,12 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/place/api_place.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:google_maps_webservice/places.dart'; import '../api/network/client.dart'; +const placeApiKey = "AIzaSyDLlL9HqzRyfVQHsNkNZjJf1ItdwvEJTOc"; + final placeServiceProvider = Provider( (ref) => PlaceService( ref.read(firestoreProvider), @@ -29,4 +32,18 @@ class PlaceService { Future deletePlace(String spaceId, String placeId) async { await spacePlacesRef(spaceId).doc(placeId).delete(); } + + Future findPlace(String text, double lat, double lng) async { + final places = GoogleMapsPlaces(apiKey: placeApiKey); + final result = await places.searchNearbyWithRadius( + Location(lat: lat, lng: lng), + 5000, + keyword: text, + ); + if (result.status == "OK") { + print('XXX data test:${result.results}'); + } else { + throw Exception(result.errorMessage); + } + } } diff --git a/data/pubspec.yaml b/data/pubspec.yaml index ac77b219..9b537ca9 100644 --- a/data/pubspec.yaml +++ b/data/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: flutter_timezone: ^1.0.8 package_info_plus: ^8.0.0 uuid: ^4.4.0 + google_maps_webservice: ^0.0.20-nullsafety.5 dev_dependencies: flutter_test: From 178dd2d9474a737c40b6506a9f7a761b34ce1851 Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 21 Jun 2024 15:29:53 +0530 Subject: [PATCH 15/65] Minor --- .../add_new_place_view_model.freezed.dart | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 app/lib/ui/flow/geofence/addplace/add_new_place_view_model.freezed.dart diff --git a/app/lib/ui/flow/geofence/addplace/add_new_place_view_model.freezed.dart b/app/lib/ui/flow/geofence/addplace/add_new_place_view_model.freezed.dart new file mode 100644 index 00000000..37e74690 --- /dev/null +++ b/app/lib/ui/flow/geofence/addplace/add_new_place_view_model.freezed.dart @@ -0,0 +1,145 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'add_new_place_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$AddNewPlaceState { + dynamic get loading => throw _privateConstructorUsedError; + Object? get error => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $AddNewPlaceStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AddNewPlaceStateCopyWith<$Res> { + factory $AddNewPlaceStateCopyWith( + AddNewPlaceState value, $Res Function(AddNewPlaceState) then) = + _$AddNewPlaceStateCopyWithImpl<$Res, AddNewPlaceState>; + @useResult + $Res call({dynamic loading, Object? error}); +} + +/// @nodoc +class _$AddNewPlaceStateCopyWithImpl<$Res, $Val extends AddNewPlaceState> + implements $AddNewPlaceStateCopyWith<$Res> { + _$AddNewPlaceStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = freezed, + Object? error = freezed, + }) { + return _then(_value.copyWith( + loading: freezed == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as dynamic, + error: freezed == error ? _value.error : error, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AddNewPlaceStateImplCopyWith<$Res> + implements $AddNewPlaceStateCopyWith<$Res> { + factory _$$AddNewPlaceStateImplCopyWith(_$AddNewPlaceStateImpl value, + $Res Function(_$AddNewPlaceStateImpl) then) = + __$$AddNewPlaceStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({dynamic loading, Object? error}); +} + +/// @nodoc +class __$$AddNewPlaceStateImplCopyWithImpl<$Res> + extends _$AddNewPlaceStateCopyWithImpl<$Res, _$AddNewPlaceStateImpl> + implements _$$AddNewPlaceStateImplCopyWith<$Res> { + __$$AddNewPlaceStateImplCopyWithImpl(_$AddNewPlaceStateImpl _value, + $Res Function(_$AddNewPlaceStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = freezed, + Object? error = freezed, + }) { + return _then(_$AddNewPlaceStateImpl( + loading: freezed == loading ? _value.loading! : loading, + error: freezed == error ? _value.error : error, + )); + } +} + +/// @nodoc + +class _$AddNewPlaceStateImpl implements _AddNewPlaceState { + const _$AddNewPlaceStateImpl({this.loading = false, this.error}); + + @override + @JsonKey() + final dynamic loading; + @override + final Object? error; + + @override + String toString() { + return 'AddNewPlaceState(loading: $loading, error: $error)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AddNewPlaceStateImpl && + const DeepCollectionEquality().equals(other.loading, loading) && + const DeepCollectionEquality().equals(other.error, error)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(loading), + const DeepCollectionEquality().hash(error)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$AddNewPlaceStateImplCopyWith<_$AddNewPlaceStateImpl> get copyWith => + __$$AddNewPlaceStateImplCopyWithImpl<_$AddNewPlaceStateImpl>( + this, _$identity); +} + +abstract class _AddNewPlaceState implements AddNewPlaceState { + const factory _AddNewPlaceState( + {final dynamic loading, final Object? error}) = _$AddNewPlaceStateImpl; + + @override + dynamic get loading; + @override + Object? get error; + @override + @JsonKey(ignore: true) + _$$AddNewPlaceStateImplCopyWith<_$AddNewPlaceStateImpl> get copyWith => + throw _privateConstructorUsedError; +} From 67054bc5610ec7663cbe934d56e57e84aadf9a22 Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 21 Jun 2024 16:04:38 +0530 Subject: [PATCH 16/65] show battery dialog once in a day --- .../ui/flow/home/home_screen_viewmodel.dart | 25 +++++++++++++++++-- data/lib/storage/app_preferences.dart | 7 +++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/lib/ui/flow/home/home_screen_viewmodel.dart b/app/lib/ui/flow/home/home_screen_viewmodel.dart index 25fad07c..5a0dbd09 100644 --- a/app/lib/ui/flow/home/home_screen_viewmodel.dart +++ b/app/lib/ui/flow/home/home_screen_viewmodel.dart @@ -14,6 +14,7 @@ final homeViewStateProvider = ref.read(spaceServiceProvider), ref.read(currentUserSessionJsonPod.notifier), ref.read(permissionServiceProvider), + ref.read(lastBatteryDialogPod.notifier), ), ); @@ -21,10 +22,14 @@ class HomeViewNotifier extends StateNotifier { final SpaceService spaceService; final PermissionService permissionService; final StateController _currentSpaceIdController; + final StateController _lastBatteryDialogDate; HomeViewNotifier( - this.spaceService, this._currentSpaceIdController, this.permissionService) - : super(const HomeViewState()); + this.spaceService, + this._currentSpaceIdController, + this.permissionService, + this._lastBatteryDialogDate, + ) : super(const HomeViewState()); String? get currentSpaceId => _currentSpaceIdController.state; @@ -91,13 +96,29 @@ class HomeViewNotifier extends StateNotifier { void showBatteryOptimizationDialog() async { // We don't want to show prompt immediately after user opens the app await Future.delayed(const Duration(seconds: 1)); + final date = _lastBatteryDialogDate.state; + if (date == null) { + _checkBatteryPermission(); + } else { + final storedDate = DateTime.parse(date); + final currentDate = DateTime.now(); + final daysPassed = currentDate.difference(storedDate).inDays; + + if (daysPassed >= 1) { + _checkBatteryPermission(); + } + } + } + + void _checkBatteryPermission() async { final isBatteryOptimization = await permissionService.isBatteryOptimizationEnabled(); final isBackgroundEnabled = await permissionService.isBackgroundLocationPermissionGranted(); if (!isBatteryOptimization && isBackgroundEnabled) { + _lastBatteryDialogDate.state = DateTime.now().toString(); state = state.copyWith(showBatteryDialog: DateTime.now()); } } diff --git a/data/lib/storage/app_preferences.dart b/data/lib/storage/app_preferences.dart index c01e8a7f..e0c7d0f7 100644 --- a/data/lib/storage/app_preferences.dart +++ b/data/lib/storage/app_preferences.dart @@ -42,4 +42,9 @@ final hasUserSession = final currentSpaceId = createPrefProvider( prefKey: "current_space_id", defaultValue: null, -); \ No newline at end of file +); + +final lastBatteryDialogPod = createPrefProvider( + prefKey: 'show_battery_dialog', + defaultValue: null, +); From b17fbc1719d6166ceca8471d2c5845a15485f51a Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 21 Jun 2024 17:22:38 +0530 Subject: [PATCH 17/65] Mr changes --- app/assets/locales/app_en.arb | 1 - .../geofence/places/places_list_view.dart | 3 +- .../places/places_list_view_model.dart | 27 +++++++++++++++ .../places_list_view_model.freezed.dart | 34 +++++++++++++++++-- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/app/assets/locales/app_en.arb b/app/assets/locales/app_en.arb index 682f2827..3f746122 100644 --- a/app/assets/locales/app_en.arb +++ b/app/assets/locales/app_en.arb @@ -147,7 +147,6 @@ }, "places_list_title": "Places", "places_list_add_place_btn_text": "Add place", - "places_list_suggestion_add_your_place":"Add your {place}", "places_list_suggestion_home_text": "Home", "places_list_suggestion_work_text": "Work", "places_list_suggestion_school_text": "School", diff --git a/app/lib/ui/flow/geofence/places/places_list_view.dart b/app/lib/ui/flow/geofence/places/places_list_view.dart index f2e8e988..4b915012 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view.dart @@ -76,8 +76,7 @@ class _PlacesViewState extends ConsumerState { final item = suggestions[placeIndex]; return _placeItemView( - placeName: - context.l10n.places_list_suggestion_add_your_place(item), + placeName: item, icon: _getPlacesIcon(item), isSuggestion: true, onDeletePlace: () {}, diff --git a/app/lib/ui/flow/geofence/places/places_list_view_model.dart b/app/lib/ui/flow/geofence/places/places_list_view_model.dart index ff3f8b0a..d8cd121c 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view_model.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view_model.dart @@ -28,6 +28,7 @@ class PlacesListViewNotifier extends StateNotifier { try { state = state.copyWith(loading: true, spaceId: spaceId); placeService.getAllPlacesStream(spaceId).listen((places) { + suggestionPlaces(places); state = state.copyWith(places: places, loading: false); }); } catch (error, stack) { @@ -40,6 +41,31 @@ class PlacesListViewNotifier extends StateNotifier { } } + void suggestionPlaces(List places) { + final suggestedPlaces = [ + 'Home', + 'Work', + 'School', + 'Gym', + 'Library', + 'Local park' + ]; + + final newSuggestedPlace = suggestedPlaces.where((suggestion) { + final suggestionName = suggestion.toLowerCase(); + + for (final place in places) { + final placeName = place.name.toLowerCase(); + if (state.currentUser?.id == place.created_by && + suggestionName == placeName) { + return false; + } + } + return true; + }).toList(); + state = state.copyWith(suggestions: newSuggestedPlace); + } + void onClickDeletePlace(ApiPlace place) { state = state.copyWith( placesToDelete: place, @@ -78,6 +104,7 @@ class PlacesListState with _$PlacesListState { ApiPlace? placesToDelete, ApiUser? currentUser, @Default([]) List places, + @Default([]) List suggestions, Object? error, }) = _PlacesListState; } diff --git a/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart b/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart index 52110eb1..b7518e6c 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart @@ -23,6 +23,7 @@ mixin _$PlacesListState { ApiPlace? get placesToDelete => throw _privateConstructorUsedError; ApiUser? get currentUser => throw _privateConstructorUsedError; List get places => throw _privateConstructorUsedError; + List get suggestions => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -44,6 +45,7 @@ abstract class $PlacesListStateCopyWith<$Res> { ApiPlace? placesToDelete, ApiUser? currentUser, List places, + List suggestions, Object? error}); $ApiPlaceCopyWith<$Res>? get placesToDelete; @@ -70,6 +72,7 @@ class _$PlacesListStateCopyWithImpl<$Res, $Val extends PlacesListState> Object? placesToDelete = freezed, Object? currentUser = freezed, Object? places = null, + Object? suggestions = null, Object? error = freezed, }) { return _then(_value.copyWith( @@ -101,6 +104,10 @@ class _$PlacesListStateCopyWithImpl<$Res, $Val extends PlacesListState> ? _value.places : places // ignore: cast_nullable_to_non_nullable as List, + suggestions: null == suggestions + ? _value.suggestions + : suggestions // ignore: cast_nullable_to_non_nullable + as List, error: freezed == error ? _value.error : error, ) as $Val); } @@ -146,6 +153,7 @@ abstract class _$$PlacesListStateImplCopyWith<$Res> ApiPlace? placesToDelete, ApiUser? currentUser, List places, + List suggestions, Object? error}); @override @@ -172,6 +180,7 @@ class __$$PlacesListStateImplCopyWithImpl<$Res> Object? placesToDelete = freezed, Object? currentUser = freezed, Object? places = null, + Object? suggestions = null, Object? error = freezed, }) { return _then(_$PlacesListStateImpl( @@ -203,6 +212,10 @@ class __$$PlacesListStateImplCopyWithImpl<$Res> ? _value._places : places // ignore: cast_nullable_to_non_nullable as List, + suggestions: null == suggestions + ? _value._suggestions + : suggestions // ignore: cast_nullable_to_non_nullable + as List, error: freezed == error ? _value.error : error, )); } @@ -219,8 +232,10 @@ class _$PlacesListStateImpl implements _PlacesListState { this.placesToDelete, this.currentUser, final List places = const [], + final List suggestions = const [], this.error}) - : _places = places; + : _places = places, + _suggestions = suggestions; @override @JsonKey() @@ -245,12 +260,21 @@ class _$PlacesListStateImpl implements _PlacesListState { return EqualUnmodifiableListView(_places); } + final List _suggestions; + @override + @JsonKey() + List get suggestions { + if (_suggestions is EqualUnmodifiableListView) return _suggestions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_suggestions); + } + @override final Object? error; @override String toString() { - return 'PlacesListState(loading: $loading, deletingPlaces: $deletingPlaces, spaceId: $spaceId, showDeletePlaceDialog: $showDeletePlaceDialog, placesToDelete: $placesToDelete, currentUser: $currentUser, places: $places, error: $error)'; + return 'PlacesListState(loading: $loading, deletingPlaces: $deletingPlaces, spaceId: $spaceId, showDeletePlaceDialog: $showDeletePlaceDialog, placesToDelete: $placesToDelete, currentUser: $currentUser, places: $places, suggestions: $suggestions, error: $error)'; } @override @@ -269,6 +293,8 @@ class _$PlacesListStateImpl implements _PlacesListState { (identical(other.currentUser, currentUser) || other.currentUser == currentUser) && const DeepCollectionEquality().equals(other._places, _places) && + const DeepCollectionEquality() + .equals(other._suggestions, _suggestions) && const DeepCollectionEquality().equals(other.error, error)); } @@ -282,6 +308,7 @@ class _$PlacesListStateImpl implements _PlacesListState { placesToDelete, currentUser, const DeepCollectionEquality().hash(_places), + const DeepCollectionEquality().hash(_suggestions), const DeepCollectionEquality().hash(error)); @JsonKey(ignore: true) @@ -301,6 +328,7 @@ abstract class _PlacesListState implements PlacesListState { final ApiPlace? placesToDelete, final ApiUser? currentUser, final List places, + final List suggestions, final Object? error}) = _$PlacesListStateImpl; @override @@ -318,6 +346,8 @@ abstract class _PlacesListState implements PlacesListState { @override List get places; @override + List get suggestions; + @override Object? get error; @override @JsonKey(ignore: true) From 71e5c789aedf4bdbe814b15e822eeefff8ac1375 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 24 Jun 2024 11:40:33 +0530 Subject: [PATCH 18/65] Mr changes --- .../extenstions/time_ago_extenstions.dart | 26 ++++++++++ .../ui/flow/home/home_screen_viewmodel.dart | 3 +- .../selected_member_detail_view.dart | 29 +---------- .../map/components/space_user_footer.dart | 5 +- app/lib/ui/flow/home/map/map_view_model.dart | 1 + data/.flutter-plugins | 50 +++++++++---------- data/.flutter-plugins-dependencies | 2 +- 7 files changed, 58 insertions(+), 58 deletions(-) create mode 100644 app/lib/domain/extenstions/time_ago_extenstions.dart diff --git a/app/lib/domain/extenstions/time_ago_extenstions.dart b/app/lib/domain/extenstions/time_ago_extenstions.dart new file mode 100644 index 00000000..614620ba --- /dev/null +++ b/app/lib/domain/extenstions/time_ago_extenstions.dart @@ -0,0 +1,26 @@ +extension TimeAgoExtension on int? { + String timeAgo() { + if (this == null) return ""; + + final DateTime now = DateTime.now(); + final DateTime date = DateTime.fromMillisecondsSinceEpoch(this!); + + final Duration diff = now.difference(date); + + if (diff.inSeconds < 60) { + return "just now"; + } else if (diff.inMinutes < 60) { + return "${diff.inMinutes} minutes ago"; + } else if (diff.inHours < 24) { + return "${diff.inHours} hours ago"; + } else if (diff.inDays < 7) { + return "${diff.inDays} days ago"; + } else if (diff.inDays < 30) { + return "${diff.inDays ~/ 7} weeks ago"; + } else if (diff.inDays < 365) { + return "${diff.inDays ~/ 30} months ago"; + } else { + return "${diff.inDays ~/ 365} years ago"; + } + } +} diff --git a/app/lib/ui/flow/home/home_screen_viewmodel.dart b/app/lib/ui/flow/home/home_screen_viewmodel.dart index a867494e..dd8a5937 100644 --- a/app/lib/ui/flow/home/home_screen_viewmodel.dart +++ b/app/lib/ui/flow/home/home_screen_viewmodel.dart @@ -29,6 +29,7 @@ class HomeViewNotifier extends StateNotifier { } void getAllSpace() async { + if (state.loading) return; try { state = state.copyWith(loading: state.spaceList.isEmpty); final spaces = await spaceService.getAllSpaceInfo(); @@ -51,7 +52,7 @@ class HomeViewNotifier extends StateNotifier { updateSelectedSpace(selectedSpace); } } catch (error, stack) { - state = state.copyWith(error: error); + state = state.copyWith(error: error, loading: false); logger.e( 'HomeViewNotifier: error while getting all spaces', error: error, diff --git a/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart b/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart index 7538ae8b..09e9656a 100644 --- a/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart +++ b/app/lib/ui/flow/home/map/components/selected_member_detail_view.dart @@ -7,6 +7,7 @@ import 'package:style/animation/on_tap_scale.dart'; import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/text/app_text_dart.dart'; import 'package:yourspace_flutter/domain/extenstions/lat_lng_extenstion.dart'; +import 'package:yourspace_flutter/domain/extenstions/time_ago_extenstions.dart'; import '../../../../../gen/assets.gen.dart'; import '../../../../components/user_battery_status.dart'; @@ -159,7 +160,6 @@ class _SelectedMemberDetailViewState extends State { } Widget _userTimeAgo(int? createdAt) { - final time = timeAgo(createdAt); return Row( children: [ Icon( @@ -169,7 +169,7 @@ class _SelectedMemberDetailViewState extends State { ), const SizedBox(width: 4), Text( - time, + createdAt.timeAgo(), style: AppTextStyle.caption .copyWith(color: context.colorScheme.textDisabled), ) @@ -177,31 +177,6 @@ class _SelectedMemberDetailViewState extends State { ); } - String timeAgo(int? timestamp) { - if (timestamp == null) return ""; - - final DateTime now = DateTime.now(); - final DateTime date = DateTime.fromMillisecondsSinceEpoch(timestamp); - - final Duration diff = now.difference(date); - - if (diff.inSeconds < 60) { - return "just now"; - } else if (diff.inMinutes < 60) { - return "${diff.inMinutes} minutes ago"; - } else if (diff.inHours < 24) { - return "${diff.inHours} hours ago"; - } else if (diff.inDays < 7) { - return "${diff.inDays} days ago"; - } else if (diff.inDays < 30) { - return "${diff.inDays ~/ 7} weeks ago"; - } else if (diff.inDays < 365) { - return "${diff.inDays ~/ 30} months ago"; - } else { - return "${diff.inDays ~/ 365} years ago"; - } - } - void getAddress(ApiLocation? location) async { if (location != null) { final latLng = LatLng(location.latitude, location.longitude); diff --git a/app/lib/ui/flow/home/map/components/space_user_footer.dart b/app/lib/ui/flow/home/map/components/space_user_footer.dart index 12f79522..3b224efa 100644 --- a/app/lib/ui/flow/home/map/components/space_user_footer.dart +++ b/app/lib/ui/flow/home/map/components/space_user_footer.dart @@ -47,7 +47,6 @@ class _SpaceUserFooterState extends State { child: Column( children: [ _mapControlBtn(context), - AnimatedSwitcher( duration: const Duration(milliseconds: 300), transitionBuilder: (Widget child, Animation animation) { @@ -56,9 +55,7 @@ class _SpaceUserFooterState extends State { begin: const Offset(0.0, 1.0), end: const Offset(0.0, 0.0), ).animate(animation), - child: ScaleTransition( - scale: animation, - child: child), + child: ScaleTransition(scale: animation, child: child), ); }, child: widget.selectedUser != null diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index fdc7af4c..279bb999 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -55,6 +55,7 @@ class MapViewNotifier extends StateNotifier { } void listenMemberLocation(String spaceId) async { + if (state.loading) return; try { state = state.copyWith(loading: true, selectedUser: null); spaceService.getMemberWithLocation(spaceId).listen((userInfo) { diff --git a/data/.flutter-plugins b/data/.flutter-plugins index ce4daee3..fbbdb450 100644 --- a/data/.flutter-plugins +++ b/data/.flutter-plugins @@ -1,26 +1,26 @@ # This is a generated file; do not edit or check into version control. -cloud_firestore=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/ -cloud_firestore_web=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/ -cloud_functions=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/ -cloud_functions_web=/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/ -device_info_plus=/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/ -firebase_auth=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/ -firebase_auth_web=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/ -firebase_core=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/ -firebase_core_web=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/ -firebase_storage=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/ -firebase_storage_web=/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/ -flutter_timezone=/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/ -google_sign_in=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in-6.2.1/ -google_sign_in_android=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.23/ -google_sign_in_ios=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/ -google_sign_in_web=/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+3/ -package_info_plus=/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/ -path_provider_linux=/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ -path_provider_windows=/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ -shared_preferences=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/ -shared_preferences_android=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/ -shared_preferences_foundation=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/ -shared_preferences_linux=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/ -shared_preferences_web=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/ -shared_preferences_windows=/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/ +cloud_firestore=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/ +cloud_firestore_web=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/ +cloud_functions=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/ +cloud_functions_web=/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/ +device_info_plus=/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/ +firebase_auth=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/ +firebase_auth_web=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/ +firebase_core=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/ +firebase_core_web=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/ +firebase_storage=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/ +firebase_storage_web=/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/ +flutter_timezone=/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/ +google_sign_in=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in-6.2.1/ +google_sign_in_android=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/ +google_sign_in_ios=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/ +google_sign_in_web=/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/ +package_info_plus=/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/ +path_provider_linux=/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ +path_provider_windows=/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ +shared_preferences=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/ +shared_preferences_android=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/ +shared_preferences_foundation=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/ +shared_preferences_linux=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/ +shared_preferences_web=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/ +shared_preferences_windows=/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/ diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index 0d340917..61e82b8b 100644 --- a/data/.flutter-plugins-dependencies +++ b/data/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.23/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"google_sign_in_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+3/","dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-06-06 12:12:52.852133","version":"3.22.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"google_sign_in_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/","dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-06-24 11:38:22.020742","version":"3.22.0"} \ No newline at end of file From 0606096a03b60fb0bc99471a4290c68922bfc731 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 24 Jun 2024 13:50:22 +0530 Subject: [PATCH 19/65] Mr changes --- .../geofence/places/places_list_view.dart | 43 +------------------ 1 file changed, 2 insertions(+), 41 deletions(-) diff --git a/app/lib/ui/flow/geofence/places/places_list_view.dart b/app/lib/ui/flow/geofence/places/places_list_view.dart index 4b915012..fdaaa6ed 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view.dart @@ -24,7 +24,6 @@ class PlacesListView extends ConsumerStatefulWidget { class _PlacesViewState extends ConsumerState { late PlacesListViewNotifier notifier; - List suggestions = []; @override void initState() { @@ -40,7 +39,6 @@ class _PlacesViewState extends ConsumerState { final state = ref.watch(placesListViewStateProvider); _observeShowDeletePlaceDialog(); - _observeCurrentUserPlaces(state); return AppPage(title: context.l10n.places_list_title, body: _body(state)); } @@ -56,7 +54,7 @@ class _PlacesViewState extends ConsumerState { children: [ Expanded( child: ListView.builder( - itemCount: placeLength + suggestions.length, + itemCount: placeLength + state.suggestions.length, itemBuilder: (_, index) { if (index < state.places.length) { return _placesListItem(state, state.places[index]); @@ -74,7 +72,7 @@ class _PlacesViewState extends ConsumerState { ? index : index - state.places.length - 1; - final item = suggestions[placeIndex]; + final item = state.suggestions[placeIndex]; return _placeItemView( placeName: item, icon: _getPlacesIcon(item), @@ -199,43 +197,6 @@ class _PlacesViewState extends ConsumerState { ); } - void _observeCurrentUserPlaces(PlacesListState state) { - ref.listen(placesListViewStateProvider.select((state) => state.places), - (_, next) { - if (next.isNotEmpty) { - final suggestedPlaces = _getSuggestionsPlaces(); - - final newSuggestedPlace = suggestedPlaces.where((suggestion) { - final suggestionName = suggestion.toLowerCase(); - - for (final place in next) { - final placeName = place.name.toLowerCase(); - if (state.currentUser?.id == place.created_by && - suggestionName == placeName) { - return false; - } - } - return true; - }).toList(); - - setState(() { - suggestions = newSuggestedPlace; - }); - } - }); - } - - List _getSuggestionsPlaces() { - return [ - context.l10n.places_list_suggestion_home_text, - context.l10n.places_list_suggestion_work_text, - context.l10n.places_list_suggestion_school_text, - context.l10n.places_list_suggestion_gym_text, - context.l10n.places_list_suggestion_library_text, - context.l10n.places_list_suggestion_local_park_text, - ]; - } - String _getPlacesIcon(String name) { if (name == 'Home') { return Assets.images.icPlacesHomeIcon; From 12ad2f478f711b3dd00298622dfaa7c067f3f019 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 24 Jun 2024 14:45:46 +0530 Subject: [PATCH 20/65] Fix multiple api call --- app/lib/ui/flow/home/home_screen.dart | 34 ++++++++++++++------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index 73245aa3..9376520b 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -44,7 +44,9 @@ class _HomeScreenState extends ConsumerState { return AppPage( body: ResumeDetector( onResume: () { + if(state.selectedSpace != null){ notifier.getAllSpace(); + } }, child: _body(context, state), ), @@ -73,30 +75,30 @@ class _HomeScreenState extends ConsumerState { void _observeNavigation(HomeViewState state) { ref.listen( homeViewStateProvider.select((state) => state.spaceInvitationCode), - (_, next) { - if (next.isNotEmpty) { - AppRoute.inviteCode( + (_, next) { + if (next.isNotEmpty) { + AppRoute.inviteCode( code: next, spaceName: state.selectedSpace?.space.name ?? '') - .push(context); - } - }); + .push(context); + } + }); } void _observeError() { ref.listen(homeViewStateProvider.select((state) => state.error), - (previous, next) { - if (next != null) { - showErrorSnackBar(context, next.toString()); - } - }); + (previous, next) { + if (next != null) { + showErrorSnackBar(context, next.toString()); + } + }); } void _observeSelectedSpace() { ref.listen(homeViewStateProvider.select((state) => state.selectedSpace), - (previous, next) { - if (previous?.space.id != next?.space.id) { - mapNotifier.loadData(next?.space.id); - } - }); + (previous, next) { + if (previous?.space.id != next?.space.id) { + mapNotifier.loadData(next?.space.id); + } + }); } } From 090309e1312ed4ee514ef9aca360c69e729cb0a3 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 24 Jun 2024 19:30:04 +0530 Subject: [PATCH 21/65] Implement screens --- app/assets/images/ic_location-feed_icon.svg | 5 + app/assets/locales/app_en.arb | 14 +- app/lib/gen/assets.gen.dart | 4 + app/lib/ui/app_route.dart | 45 +++- .../addnew}/add_new_place_view.dart | 73 +++--- .../addnew}/add_new_place_view_model.dart | 2 +- .../add_new_place_view_model.freezed.dart | 0 .../add/locate/locate_on_map_view.dart | 129 +++++++++++ .../add/locate/locate_on_map_view_model.dart | 27 +++ .../locate_on_map_view_model.freezed.dart | 153 +++++++++++++ .../add/placename/choose_place_name_view.dart | 165 ++++++++++++++ .../choose_place_name_view_model.dart | 82 +++++++ .../choose_place_name_view_model.freezed.dart | 208 ++++++++++++++++++ app/lib/ui/flow/home/home_screen.dart | 4 +- app/lib/ui/flow/home/map/map_view_model.dart | 1 - data/lib/service/place_service.dart | 23 +- data/pubspec.yaml | 1 - 17 files changed, 875 insertions(+), 61 deletions(-) create mode 100644 app/assets/images/ic_location-feed_icon.svg rename app/lib/ui/flow/geofence/{addplace => add/addnew}/add_new_place_view.dart (62%) rename app/lib/ui/flow/geofence/{addplace => add/addnew}/add_new_place_view_model.dart (96%) rename app/lib/ui/flow/geofence/{addplace => add/addnew}/add_new_place_view_model.freezed.dart (100%) create mode 100644 app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart create mode 100644 app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.dart create mode 100644 app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.freezed.dart create mode 100644 app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart create mode 100644 app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart create mode 100644 app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart diff --git a/app/assets/images/ic_location-feed_icon.svg b/app/assets/images/ic_location-feed_icon.svg new file mode 100644 index 00000000..aa2eb9e8 --- /dev/null +++ b/app/assets/images/ic_location-feed_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/assets/locales/app_en.arb b/app/assets/locales/app_en.arb index 3f746122..eb28ca45 100644 --- a/app/assets/locales/app_en.arb +++ b/app/assets/locales/app_en.arb @@ -153,5 +153,17 @@ "places_list_suggestion_gym_text": "Gym", "places_list_suggestion_library_text": "Library", "places_list_suggestion_local_park_text": "Local park", - "places_list_delete_dialog_content_text": "Are you sure you want to delete this place? This action cannot be undone." + "places_list_delete_dialog_content_text": "Are you sure you want to delete this place? This action cannot be undone.", + + "add_new_place_title": "Add a new place", + "add_new_place_suggestion_text": "Some suggestions...", + "add_new_place_search_hint_text": "Search address and location name", + "add_new_place_location_on_map_text": "Locate on map", + + "locate_on_map_title": "Locate on Map", + + "choose_place_screen_title": "Choose place name", + "choose_place_search_hint_text": "Enter place name", + "choose_place_suggestion_text": "Some suggestions...", + "choose_place_add_place_btn_text": "Add place" } \ No newline at end of file diff --git a/app/lib/gen/assets.gen.dart b/app/lib/gen/assets.gen.dart index 738045c0..28941765 100644 --- a/app/lib/gen/assets.gen.dart +++ b/app/lib/gen/assets.gen.dart @@ -55,6 +55,9 @@ class $AssetsImagesGen { /// File path: assets/images/ic_google_logo.svg String get icGoogleLogo => 'assets/images/ic_google_logo.svg'; + /// File path: assets/images/ic_location-feed_icon.svg + String get icLocationFeedIcon => 'assets/images/ic_location-feed_icon.svg'; + /// File path: assets/images/ic_location.svg String get icLocation => 'assets/images/ic_location.svg'; @@ -134,6 +137,7 @@ class $AssetsImagesGen { icFullBetteryIcon, icGeofenceIcon, icGoogleLogo, + icLocationFeedIcon, icLocation, icMessage, icPlaceMarkerIcon, diff --git a/app/lib/ui/app_route.dart b/app/lib/ui/app_route.dart index 7aa64fba..d4ee65e4 100644 --- a/app/lib/ui/app_route.dart +++ b/app/lib/ui/app_route.dart @@ -1,6 +1,9 @@ import 'package:flutter/cupertino.dart'; import 'package:go_router/go_router.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:yourspace_flutter/ui/flow/auth/sign_in/phone/verification/phone_verification_screen.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/add/locate/locate_on_map_view.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_name_view.dart'; import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_view.dart'; import 'package:yourspace_flutter/ui/flow/onboard/pick_name_screen.dart'; import 'package:yourspace_flutter/ui/flow/setting/contact_support/contact_support_screen.dart'; @@ -13,7 +16,7 @@ import 'package:yourspace_flutter/ui/flow/space/join/join_space_screen.dart'; import 'flow/auth/sign_in/phone/sign_in_with_phone_screen.dart'; import 'flow/auth/sign_in/sign_in_method_screen.dart'; -import 'flow/geofence/addplace/add_new_place_view.dart'; +import 'flow/geofence/add/addnew/add_new_place_view.dart'; import 'flow/home/home_screen.dart'; import 'flow/intro/intro_screen.dart'; @@ -27,7 +30,9 @@ class AppRoute { static const pathEditSpace = '/space'; static const pathContactSupport = '/contact-support'; static const pathPlacesList = '/places-list'; - static const pathAddNewPlace = '/add_new_place'; + static const pathAddNewPlace = '/add-new-place'; + static const pathLocateOnMap = "/locate_on_map"; + static const pathChoosePlace = "/choose_place"; final String path; final String? name; @@ -168,15 +173,29 @@ class AppRoute { ); } + static AppRoute locateOnMapScreen(String spaceId) { + return AppRoute(pathLocateOnMap, + builder: (_) => LocateOnMapView(spaceId: spaceId)); + } + + static AppRoute choosePlaceName(LatLng location, String spaceId) { + return AppRoute( + pathChoosePlace, + builder: (_) => ChoosePlaceNameView( + location: location, + spaceId: spaceId, + ), + ); + } + static final routes = [ GoRoute( - path: intro.path, - builder: (context, state) { - return state.extra == null - ? const IntroScreen() - : state.widget(context); - }, - ), + path: intro.path, + builder: (context, state) { + return state.extra == null + ? const IntroScreen() + : state.widget(context); + }), GoRoute( path: pickName.path, builder: (context, state) { @@ -242,6 +261,14 @@ class AppRoute { GoRoute( path: pathAddNewPlace, builder: (context, state) => state.widget(context), + ), + GoRoute( + path: pathLocateOnMap, + builder: (context, state) => state.widget(context), + ), + GoRoute( + path: pathChoosePlace, + builder: (context, state) => state.widget(context), ) ]; } diff --git a/app/lib/ui/flow/geofence/addplace/add_new_place_view.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart similarity index 62% rename from app/lib/ui/flow/geofence/addplace/add_new_place_view.dart rename to app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart index c76a731a..39341fe0 100644 --- a/app/lib/ui/flow/geofence/addplace/add_new_place_view.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart @@ -1,12 +1,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:style/animation/on_tap_scale.dart'; import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; +import 'package:yourspace_flutter/ui/app_route.dart'; import 'package:yourspace_flutter/ui/components/app_page.dart'; -import 'package:yourspace_flutter/ui/flow/geofence/addplace/add_new_place_view_model.dart'; -import '../../../../gen/assets.gen.dart'; +import '../../../../../gen/assets.gen.dart'; +import 'add_new_place_view_model.dart'; class AddNewPlaceView extends ConsumerStatefulWidget { final String spaceId; @@ -20,13 +23,12 @@ class AddNewPlaceView extends ConsumerStatefulWidget { class _AddNewPlaceViewState extends ConsumerState { late AddNewPlaceViewNotifier notifier; - @override Widget build(BuildContext context) { notifier = ref.watch(addNewPLaceStateProvider.notifier); return AppPage( - title: "Add a new place", + title: context.l10n.add_new_place_title, body: _body(), ); } @@ -42,7 +44,7 @@ class _AddNewPlaceViewState extends ConsumerState { _locateOnMapView(), const SizedBox(height: 40), Text( - "Some suggestions...", + context.l10n.add_new_place_suggestion_text, style: AppTextStyle.caption.copyWith( color: context.colorScheme.textDisabled, ), @@ -69,7 +71,7 @@ class _AddNewPlaceViewState extends ConsumerState { color: context.colorScheme.textDisabled, ), ), - hintText: 'Search address and location name', + hintText: context.l10n.add_new_place_search_hint_text, hintStyle: AppTextStyle.subtitle3.copyWith( color: context.colorScheme.textDisabled, ), @@ -95,35 +97,40 @@ class _AddNewPlaceViewState extends ConsumerState { } Widget _locateOnMapView() { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: context.colorScheme.containerNormal, - ), - child: Row( - children: [ - Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(30), - color: context.colorScheme.containerLow), - child: SvgPicture.asset( - Assets.images.icLocation, - colorFilter: ColorFilter.mode( - context.colorScheme.textPrimary, - BlendMode.srcATop, + return OnTapScale( + onTap: () { + AppRoute.locateOnMapScreen(widget.spaceId).push(context); + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: context.colorScheme.containerNormal, + ), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: context.colorScheme.containerLow), + child: SvgPicture.asset( + Assets.images.icLocation, + colorFilter: ColorFilter.mode( + context.colorScheme.textPrimary, + BlendMode.srcATop, + ), ), ), - ), - const SizedBox(width: 16), - Text( - "Locate on map", - style: AppTextStyle.subtitle3.copyWith( - color: context.colorScheme.textPrimary, - ), - ) - ], + const SizedBox(width: 16), + Text( + context.l10n.add_new_place_location_on_map_text, + style: AppTextStyle.subtitle3.copyWith( + color: context.colorScheme.textPrimary, + ), + ) + ], + ), ), ); } diff --git a/app/lib/ui/flow/geofence/addplace/add_new_place_view_model.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart similarity index 96% rename from app/lib/ui/flow/geofence/addplace/add_new_place_view_model.dart rename to app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart index 50a05c4f..804928c3 100644 --- a/app/lib/ui/flow/geofence/addplace/add_new_place_view_model.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart @@ -30,7 +30,7 @@ class AddNewPlaceViewNotifier extends StateNotifier { void fidePlace(String value) async { try { state = state.copyWith(loading: true); - await placeService.findPlace(value,0.0,0.0); + // todo call get places api here. } catch (error, stack) { state = state.copyWith(error: error, loading: false); logger.e( diff --git a/app/lib/ui/flow/geofence/addplace/add_new_place_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart similarity index 100% rename from app/lib/ui/flow/geofence/addplace/add_new_place_view_model.freezed.dart rename to app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart diff --git a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart new file mode 100644 index 00000000..cf91abef --- /dev/null +++ b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart @@ -0,0 +1,129 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:style/animation/on_tap_scale.dart'; +import 'package:style/button/icon_primary_button.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; +import 'package:yourspace_flutter/ui/app_route.dart'; +import 'package:yourspace_flutter/ui/components/app_page.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/add/locate/locate_on_map_view_model.dart'; + +import '../../../../../gen/assets.gen.dart'; +import '../../../home/map/map_view.dart'; + +class LocateOnMapView extends ConsumerStatefulWidget { + final String spaceId; + + const LocateOnMapView({super.key, required this.spaceId}); + + @override + ConsumerState createState() => _LocateOnMapViewState(); +} + +class _LocateOnMapViewState extends ConsumerState { + late LocateOnMapVieNotifier notifier; + final _cameraPosition = + const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); + + @override + Widget build(BuildContext context) { + notifier = ref.watch(locateOnMapViewStateProvider.notifier); + final state = ref.watch(locateOnMapViewStateProvider); + final centerPosition = state.centerPosition; + final enable = centerPosition != null + ? centerPosition.target != _cameraPosition.target + : false; + + return AppPage( + title: context.l10n.locate_on_map_title, + actions: [ + OnTapScale( + enabled: enable, + onTap: () { + if (centerPosition != null) { + AppRoute.choosePlaceName(centerPosition.target, widget.spaceId) + .push(context); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + context.l10n.common_next, + style: AppTextStyle.button.copyWith( + color: enable + ? context.colorScheme.primary + : context.colorScheme.textDisabled, + ), + ), + ), + ) + ], + body: _body(), + ); + } + + Widget _body() { + return Padding( + padding: + EdgeInsets.only(top: 16, bottom: context.mediaQueryPadding.bottom), + child: Stack(children: [ + Center( + child: GoogleMap( + initialCameraPosition: _cameraPosition, + compassEnabled: false, + zoomControlsEnabled: false, + tiltGesturesEnabled: false, + myLocationButtonEnabled: false, + mapToolbarEnabled: false, + buildingsEnabled: false, + onCameraMove: notifier.showLocateBtn, + ), + ), + Center(child: _centerLocateView()), + Align( + alignment: Alignment.bottomRight, child: _locateIconButton(context)) + ]), + ); + } + + Widget _centerLocateView() { + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: context.colorScheme.onPrimary, + ), + child: Padding( + padding: const EdgeInsets.all(4), + child: SvgPicture.asset( + Assets.images.icLocationFeedIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.primary, + BlendMode.srcATop, + ), + ), + ), + ); + } + + Widget _locateIconButton(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), + child: IconPrimaryButton( + backgroundColor: context.colorScheme.onPrimary, + onTap: () {}, + icon: SvgPicture.asset( + Assets.images.icRelocateIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.primary, + BlendMode.srcATop, + ), + ), + ), + ); + } +} diff --git a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.dart b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.dart new file mode 100644 index 00000000..fdd20126 --- /dev/null +++ b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.dart @@ -0,0 +1,27 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +part 'locate_on_map_view_model.freezed.dart'; + +final locateOnMapViewStateProvider = + StateNotifierProvider.autoDispose( + (ref) { + return LocateOnMapVieNotifier(); +}); + +class LocateOnMapVieNotifier extends StateNotifier { + LocateOnMapVieNotifier() : super(const LocateOnMapState()); + + void showLocateBtn(CameraPosition position) { + state = state.copyWith(centerPosition: position); + } +} + +@freezed +class LocateOnMapState with _$LocateOnMapState { + const factory LocateOnMapState({ + @Default(false) bool loading, + CameraPosition? centerPosition, + }) = _LocateOnMapState; +} diff --git a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.freezed.dart new file mode 100644 index 00000000..b884306a --- /dev/null +++ b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.freezed.dart @@ -0,0 +1,153 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'locate_on_map_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$LocateOnMapState { + bool get loading => throw _privateConstructorUsedError; + CameraPosition? get centerPosition => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $LocateOnMapStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LocateOnMapStateCopyWith<$Res> { + factory $LocateOnMapStateCopyWith( + LocateOnMapState value, $Res Function(LocateOnMapState) then) = + _$LocateOnMapStateCopyWithImpl<$Res, LocateOnMapState>; + @useResult + $Res call({bool loading, CameraPosition? centerPosition}); +} + +/// @nodoc +class _$LocateOnMapStateCopyWithImpl<$Res, $Val extends LocateOnMapState> + implements $LocateOnMapStateCopyWith<$Res> { + _$LocateOnMapStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = null, + Object? centerPosition = freezed, + }) { + return _then(_value.copyWith( + loading: null == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as bool, + centerPosition: freezed == centerPosition + ? _value.centerPosition + : centerPosition // ignore: cast_nullable_to_non_nullable + as CameraPosition?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$LocateOnMapStateImplCopyWith<$Res> + implements $LocateOnMapStateCopyWith<$Res> { + factory _$$LocateOnMapStateImplCopyWith(_$LocateOnMapStateImpl value, + $Res Function(_$LocateOnMapStateImpl) then) = + __$$LocateOnMapStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({bool loading, CameraPosition? centerPosition}); +} + +/// @nodoc +class __$$LocateOnMapStateImplCopyWithImpl<$Res> + extends _$LocateOnMapStateCopyWithImpl<$Res, _$LocateOnMapStateImpl> + implements _$$LocateOnMapStateImplCopyWith<$Res> { + __$$LocateOnMapStateImplCopyWithImpl(_$LocateOnMapStateImpl _value, + $Res Function(_$LocateOnMapStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = null, + Object? centerPosition = freezed, + }) { + return _then(_$LocateOnMapStateImpl( + loading: null == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as bool, + centerPosition: freezed == centerPosition + ? _value.centerPosition + : centerPosition // ignore: cast_nullable_to_non_nullable + as CameraPosition?, + )); + } +} + +/// @nodoc + +class _$LocateOnMapStateImpl implements _LocateOnMapState { + const _$LocateOnMapStateImpl({this.loading = false, this.centerPosition}); + + @override + @JsonKey() + final bool loading; + @override + final CameraPosition? centerPosition; + + @override + String toString() { + return 'LocateOnMapState(loading: $loading, centerPosition: $centerPosition)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LocateOnMapStateImpl && + (identical(other.loading, loading) || other.loading == loading) && + (identical(other.centerPosition, centerPosition) || + other.centerPosition == centerPosition)); + } + + @override + int get hashCode => Object.hash(runtimeType, loading, centerPosition); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LocateOnMapStateImplCopyWith<_$LocateOnMapStateImpl> get copyWith => + __$$LocateOnMapStateImplCopyWithImpl<_$LocateOnMapStateImpl>( + this, _$identity); +} + +abstract class _LocateOnMapState implements LocateOnMapState { + const factory _LocateOnMapState( + {final bool loading, + final CameraPosition? centerPosition}) = _$LocateOnMapStateImpl; + + @override + bool get loading; + @override + CameraPosition? get centerPosition; + @override + @JsonKey(ignore: true) + _$$LocateOnMapStateImplCopyWith<_$LocateOnMapStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart new file mode 100644 index 00000000..a488f750 --- /dev/null +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart @@ -0,0 +1,165 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:style/animation/on_tap_scale.dart'; +import 'package:style/button/primary_button.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; +import 'package:yourspace_flutter/ui/components/app_page.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_name_view_model.dart'; + +import '../../../../../domain/extenstions/widget_extensions.dart'; + +class ChoosePlaceNameView extends ConsumerStatefulWidget { + final LatLng location; + final String spaceId; + + const ChoosePlaceNameView({ + super.key, + required this.location, + required this.spaceId, + }); + + @override + ConsumerState createState() => + _ChoosePlaceNameViewState(); +} + +class _ChoosePlaceNameViewState extends ConsumerState { + late ChoosePlaceNameViewNotifier notifier; + final _textController = TextEditingController(); + List suggestion = []; + + @override + void initState() { + super.initState(); + runPostFrame(() { + notifier = ref.watch(choosePlaceViewStateProvider.notifier); + notifier.setData(widget.location, widget.spaceId); + }); + } + + @override + Widget build(BuildContext context) { + return AppPage( + title: context.l10n.choose_place_screen_title, + body: _body(), + ); + } + + Widget _body() { + final state = ref.watch(choosePlaceViewStateProvider); + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _searchTextField(), + const SizedBox(height: 40), + Text( + context.l10n.choose_place_suggestion_text, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), + ), + const SizedBox(height: 16), + _suggestionsView(state.suggestions), + const Spacer(), + Align( + alignment: Alignment.center, + child: _addPlaceView(state), + ) + ], + ), + ); + } + + Widget _searchTextField() { + return Column( + children: [ + TextField( + controller: _textController, + style: AppTextStyle.subtitle3, + decoration: InputDecoration( + prefixIcon: Padding( + padding: const EdgeInsets.only(right: 8), + child: Icon( + Icons.search, + color: context.colorScheme.textDisabled, + ), + ), + hintText: context.l10n.choose_place_search_hint_text, + hintStyle: AppTextStyle.subtitle3.copyWith( + color: context.colorScheme.textDisabled, + ), + contentPadding: const EdgeInsets.symmetric(vertical: 0), + prefixIconConstraints: const BoxConstraints( + minHeight: 0, + minWidth: 0, + ), + border: UnderlineInputBorder( + borderSide: BorderSide( + color: context.colorScheme.textDisabled, + ), + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: context.colorScheme.primary, + ), + ), + ), + ), + ], + ); + } + + Widget _suggestionsView(List? suggestions) { + if (suggestions == null) return Container(); + return Wrap( + alignment: WrapAlignment.start, + spacing: 8, + children: suggestions.map((element) { + return OnTapScale( + onTap: () { + setState(() { + _textController.text = element; + }); + }, + child: Chip( + label: Text( + element, + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.textSecondary), + ), + labelPadding: const EdgeInsets.symmetric( + horizontal: 16, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + backgroundColor: context.colorScheme.containerLowOnSurface, + side: const BorderSide(color: Colors.transparent), + ), + ); + }).toList(), + ); + } + + Widget _addPlaceView(ChoosePlaceViewState state) { + final enable = _textController.text.isNotEmpty && !state.addingPlace; + return Padding( + padding: EdgeInsets.only(bottom: context.mediaQueryPadding.bottom + 24), + child: PrimaryButton( + enabled: enable, + progress: state.addingPlace, + onPressed: () { + notifier.onTapAddPlaceBtn(_textController.text); + }, + edgeInsets: const EdgeInsets.symmetric(horizontal: 40, vertical: 16), + context.l10n.choose_place_add_place_btn_text, + expanded: false, + ), + ); + } +} diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart new file mode 100644 index 00000000..9357fb28 --- /dev/null +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart @@ -0,0 +1,82 @@ +import 'package:data/api/auth/auth_models.dart'; +import 'package:data/log/logger.dart'; +import 'package:data/service/place_service.dart'; +import 'package:data/service/space_service.dart'; +import 'package:data/storage/app_preferences.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +part 'choose_place_name_view_model.freezed.dart'; + +final choosePlaceViewStateProvider = StateNotifierProvider.autoDispose< + ChoosePlaceNameViewNotifier, ChoosePlaceViewState>((ref) { + return ChoosePlaceNameViewNotifier( + ref.read(currentUserPod), + ref.read(placeServiceProvider), + ref.read(spaceServiceProvider), + ); +}); + +class ChoosePlaceNameViewNotifier extends StateNotifier { + final ApiUser? _currentUser; + final PlaceService placesService; + final SpaceService spaceService; + + LatLng? _location; + String? _spaceId; + + ChoosePlaceNameViewNotifier( + this._currentUser, this.placesService, this.spaceService) + : super(const ChoosePlaceViewState()); + + void setData(LatLng position, String spaceId) { + final suggestionList = [ + 'Home', + 'Work', + 'School', + 'Gym', + 'Park', + 'Grocery Store', + 'Shop', + 'Cafe', + 'Restaurant' + ]; + _location = position; + _spaceId = spaceId; + state = state.copyWith(suggestions: suggestionList); + } + + void onTapAddPlaceBtn(String value) async { + try { + final members = await spaceService.getMemberBySpaceId(_spaceId!); + final memberIds = members.map((member) => member.id).toList(); + + await placesService.addPlace( + _spaceId!, + value, + _location!.latitude, + _location!.longitude, + _currentUser!.id, + memberIds, + ); + + } catch (error, stack) { + state = state.copyWith(addingPlace: false, error: error); + logger.e( + 'ChoosePlacesNameViewNotifier: Error while adding place', + error: error, + stackTrace: stack, + ); + } + } +} + +@freezed +class ChoosePlaceViewState with _$ChoosePlaceViewState { + const factory ChoosePlaceViewState( + {@Default(false) addingPlace, + List? suggestions, + String? placeName, + Object? error}) = _ChoosePlaceViewState; +} diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart new file mode 100644 index 00000000..b7b88292 --- /dev/null +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart @@ -0,0 +1,208 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'choose_place_name_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$ChoosePlaceViewState { + dynamic get addingPlace => throw _privateConstructorUsedError; + List? get suggestions => throw _privateConstructorUsedError; + String? get placeName => throw _privateConstructorUsedError; + Object? get error => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $ChoosePlaceViewStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChoosePlaceViewStateCopyWith<$Res> { + factory $ChoosePlaceViewStateCopyWith(ChoosePlaceViewState value, + $Res Function(ChoosePlaceViewState) then) = + _$ChoosePlaceViewStateCopyWithImpl<$Res, ChoosePlaceViewState>; + @useResult + $Res call( + {dynamic addingPlace, + List? suggestions, + String? placeName, + Object? error}); +} + +/// @nodoc +class _$ChoosePlaceViewStateCopyWithImpl<$Res, + $Val extends ChoosePlaceViewState> + implements $ChoosePlaceViewStateCopyWith<$Res> { + _$ChoosePlaceViewStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? addingPlace = freezed, + Object? suggestions = freezed, + Object? placeName = freezed, + Object? error = freezed, + }) { + return _then(_value.copyWith( + addingPlace: freezed == addingPlace + ? _value.addingPlace + : addingPlace // ignore: cast_nullable_to_non_nullable + as dynamic, + suggestions: freezed == suggestions + ? _value.suggestions + : suggestions // ignore: cast_nullable_to_non_nullable + as List?, + placeName: freezed == placeName + ? _value.placeName + : placeName // ignore: cast_nullable_to_non_nullable + as String?, + error: freezed == error ? _value.error : error, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ChoosePlaceViewStateImplCopyWith<$Res> + implements $ChoosePlaceViewStateCopyWith<$Res> { + factory _$$ChoosePlaceViewStateImplCopyWith(_$ChoosePlaceViewStateImpl value, + $Res Function(_$ChoosePlaceViewStateImpl) then) = + __$$ChoosePlaceViewStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {dynamic addingPlace, + List? suggestions, + String? placeName, + Object? error}); +} + +/// @nodoc +class __$$ChoosePlaceViewStateImplCopyWithImpl<$Res> + extends _$ChoosePlaceViewStateCopyWithImpl<$Res, _$ChoosePlaceViewStateImpl> + implements _$$ChoosePlaceViewStateImplCopyWith<$Res> { + __$$ChoosePlaceViewStateImplCopyWithImpl(_$ChoosePlaceViewStateImpl _value, + $Res Function(_$ChoosePlaceViewStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? addingPlace = freezed, + Object? suggestions = freezed, + Object? placeName = freezed, + Object? error = freezed, + }) { + return _then(_$ChoosePlaceViewStateImpl( + addingPlace: freezed == addingPlace ? _value.addingPlace! : addingPlace, + suggestions: freezed == suggestions + ? _value._suggestions + : suggestions // ignore: cast_nullable_to_non_nullable + as List?, + placeName: freezed == placeName + ? _value.placeName + : placeName // ignore: cast_nullable_to_non_nullable + as String?, + error: freezed == error ? _value.error : error, + )); + } +} + +/// @nodoc + +class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { + const _$ChoosePlaceViewStateImpl( + {this.addingPlace = false, + final List? suggestions, + this.placeName, + this.error}) + : _suggestions = suggestions; + + @override + @JsonKey() + final dynamic addingPlace; + final List? _suggestions; + @override + List? get suggestions { + final value = _suggestions; + if (value == null) return null; + if (_suggestions is EqualUnmodifiableListView) return _suggestions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + final String? placeName; + @override + final Object? error; + + @override + String toString() { + return 'ChoosePlaceViewState(addingPlace: $addingPlace, suggestions: $suggestions, placeName: $placeName, error: $error)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChoosePlaceViewStateImpl && + const DeepCollectionEquality() + .equals(other.addingPlace, addingPlace) && + const DeepCollectionEquality() + .equals(other._suggestions, _suggestions) && + (identical(other.placeName, placeName) || + other.placeName == placeName) && + const DeepCollectionEquality().equals(other.error, error)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(addingPlace), + const DeepCollectionEquality().hash(_suggestions), + placeName, + const DeepCollectionEquality().hash(error)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChoosePlaceViewStateImplCopyWith<_$ChoosePlaceViewStateImpl> + get copyWith => + __$$ChoosePlaceViewStateImplCopyWithImpl<_$ChoosePlaceViewStateImpl>( + this, _$identity); +} + +abstract class _ChoosePlaceViewState implements ChoosePlaceViewState { + const factory _ChoosePlaceViewState( + {final dynamic addingPlace, + final List? suggestions, + final String? placeName, + final Object? error}) = _$ChoosePlaceViewStateImpl; + + @override + dynamic get addingPlace; + @override + List? get suggestions; + @override + String? get placeName; + @override + Object? get error; + @override + @JsonKey(ignore: true) + _$$ChoosePlaceViewStateImplCopyWith<_$ChoosePlaceViewStateImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index 9376520b..acbd4ce1 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -44,8 +44,8 @@ class _HomeScreenState extends ConsumerState { return AppPage( body: ResumeDetector( onResume: () { - if(state.selectedSpace != null){ - notifier.getAllSpace(); + if (state.selectedSpace != null) { + notifier.getAllSpace(); } }, child: _body(context, state), diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index 5b1ca375..08bfadc4 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -171,7 +171,6 @@ class MapViewNotifier extends StateNotifier { } void showMemberDetail(ApiUserInfo member) { - print('XXX user:${member.location}'); final selectedMember = (state.selectedUser?.user.id == member.user.id) ? null : member; final position = (selectedMember != null && selectedMember.location != null) diff --git a/data/lib/service/place_service.dart b/data/lib/service/place_service.dart index 9d087095..3e6ac5a1 100644 --- a/data/lib/service/place_service.dart +++ b/data/lib/service/place_service.dart @@ -1,7 +1,6 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/place/api_place.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:google_maps_webservice/places.dart'; import '../api/network/client.dart'; @@ -33,17 +32,15 @@ class PlaceService { await spacePlacesRef(spaceId).doc(placeId).delete(); } - Future findPlace(String text, double lat, double lng) async { - final places = GoogleMapsPlaces(apiKey: placeApiKey); - final result = await places.searchNearbyWithRadius( - Location(lat: lat, lng: lng), - 5000, - keyword: text, - ); - if (result.status == "OK") { - print('XXX data test:${result.results}'); - } else { - throw Exception(result.errorMessage); - } + Future addPlace( + String spaceId, + String name, + double latitude, + double longitude, + String createdBy, + List spaceMemberIds, + ) async { + + } } diff --git a/data/pubspec.yaml b/data/pubspec.yaml index 9b537ca9..ac77b219 100644 --- a/data/pubspec.yaml +++ b/data/pubspec.yaml @@ -23,7 +23,6 @@ dependencies: flutter_timezone: ^1.0.8 package_info_plus: ^8.0.0 uuid: ^4.4.0 - google_maps_webservice: ^0.0.20-nullsafety.5 dev_dependencies: flutter_test: From 5bacbca1771478967cd173984f0c2ef9bde88a97 Mon Sep 17 00:00:00 2001 From: kaushik Date: Tue, 25 Jun 2024 14:31:26 +0530 Subject: [PATCH 22/65] Fix add places --- app/assets/locales/app_en.arb | 5 +- .../add_new_place_view_model.freezed.dart | 145 ----- .../add/placename/choose_place_name_view.dart | 111 +++- .../choose_place_name_view_model.dart | 16 +- .../choose_place_name_view_model.freezed.dart | 208 ------- .../places_list_view_model.freezed.dart | 491 --------------- .../flow/home/map/map_view_model.freezed.dart | 572 ------------------ data/lib/api/place/api_place.dart | 2 + data/lib/service/place_service.dart | 36 ++ 9 files changed, 162 insertions(+), 1424 deletions(-) delete mode 100644 app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart delete mode 100644 app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart delete mode 100644 app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart delete mode 100644 app/lib/ui/flow/home/map/map_view_model.freezed.dart diff --git a/app/assets/locales/app_en.arb b/app/assets/locales/app_en.arb index eb28ca45..eceac603 100644 --- a/app/assets/locales/app_en.arb +++ b/app/assets/locales/app_en.arb @@ -165,5 +165,8 @@ "choose_place_screen_title": "Choose place name", "choose_place_search_hint_text": "Enter place name", "choose_place_suggestion_text": "Some suggestions...", - "choose_place_add_place_btn_text": "Add place" + "choose_place_add_place_btn_text": "Add place", + "choose_place_prompt_added_title_text": "{placeName} Added", + "choose_place_prompt_sub_title_text": "You will be notified when members of your space arrive/leave this place", + "choose_place_prompt_got_it_btn_text": "Got it" } \ No newline at end of file diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart deleted file mode 100644 index 37e74690..00000000 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart +++ /dev/null @@ -1,145 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'add_new_place_view_model.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -/// @nodoc -mixin _$AddNewPlaceState { - dynamic get loading => throw _privateConstructorUsedError; - Object? get error => throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $AddNewPlaceStateCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $AddNewPlaceStateCopyWith<$Res> { - factory $AddNewPlaceStateCopyWith( - AddNewPlaceState value, $Res Function(AddNewPlaceState) then) = - _$AddNewPlaceStateCopyWithImpl<$Res, AddNewPlaceState>; - @useResult - $Res call({dynamic loading, Object? error}); -} - -/// @nodoc -class _$AddNewPlaceStateCopyWithImpl<$Res, $Val extends AddNewPlaceState> - implements $AddNewPlaceStateCopyWith<$Res> { - _$AddNewPlaceStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? loading = freezed, - Object? error = freezed, - }) { - return _then(_value.copyWith( - loading: freezed == loading - ? _value.loading - : loading // ignore: cast_nullable_to_non_nullable - as dynamic, - error: freezed == error ? _value.error : error, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$AddNewPlaceStateImplCopyWith<$Res> - implements $AddNewPlaceStateCopyWith<$Res> { - factory _$$AddNewPlaceStateImplCopyWith(_$AddNewPlaceStateImpl value, - $Res Function(_$AddNewPlaceStateImpl) then) = - __$$AddNewPlaceStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({dynamic loading, Object? error}); -} - -/// @nodoc -class __$$AddNewPlaceStateImplCopyWithImpl<$Res> - extends _$AddNewPlaceStateCopyWithImpl<$Res, _$AddNewPlaceStateImpl> - implements _$$AddNewPlaceStateImplCopyWith<$Res> { - __$$AddNewPlaceStateImplCopyWithImpl(_$AddNewPlaceStateImpl _value, - $Res Function(_$AddNewPlaceStateImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? loading = freezed, - Object? error = freezed, - }) { - return _then(_$AddNewPlaceStateImpl( - loading: freezed == loading ? _value.loading! : loading, - error: freezed == error ? _value.error : error, - )); - } -} - -/// @nodoc - -class _$AddNewPlaceStateImpl implements _AddNewPlaceState { - const _$AddNewPlaceStateImpl({this.loading = false, this.error}); - - @override - @JsonKey() - final dynamic loading; - @override - final Object? error; - - @override - String toString() { - return 'AddNewPlaceState(loading: $loading, error: $error)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$AddNewPlaceStateImpl && - const DeepCollectionEquality().equals(other.loading, loading) && - const DeepCollectionEquality().equals(other.error, error)); - } - - @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(loading), - const DeepCollectionEquality().hash(error)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$AddNewPlaceStateImplCopyWith<_$AddNewPlaceStateImpl> get copyWith => - __$$AddNewPlaceStateImplCopyWithImpl<_$AddNewPlaceStateImpl>( - this, _$identity); -} - -abstract class _AddNewPlaceState implements AddNewPlaceState { - const factory _AddNewPlaceState( - {final dynamic loading, final Object? error}) = _$AddNewPlaceStateImpl; - - @override - dynamic get loading; - @override - Object? get error; - @override - @JsonKey(ignore: true) - _$$AddNewPlaceStateImplCopyWith<_$AddNewPlaceStateImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart index a488f750..591abace 100644 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart @@ -1,15 +1,19 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:style/animation/on_tap_scale.dart'; import 'package:style/button/primary_button.dart'; import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/text/app_text_dart.dart'; import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; +import 'package:yourspace_flutter/ui/app_route.dart'; import 'package:yourspace_flutter/ui/components/app_page.dart'; import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_name_view_model.dart'; import '../../../../../domain/extenstions/widget_extensions.dart'; +import '../../../../../gen/assets.gen.dart'; +import '../../../home/map/map_view.dart'; class ChoosePlaceNameView extends ConsumerStatefulWidget { final LatLng location; @@ -29,7 +33,6 @@ class ChoosePlaceNameView extends ConsumerStatefulWidget { class _ChoosePlaceNameViewState extends ConsumerState { late ChoosePlaceNameViewNotifier notifier; final _textController = TextEditingController(); - List suggestion = []; @override void initState() { @@ -42,6 +45,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { @override Widget build(BuildContext context) { + _observePopToPlacesListScreen(); return AppPage( title: context.l10n.choose_place_screen_title, body: _body(), @@ -162,4 +166,109 @@ class _ChoosePlaceNameViewState extends ConsumerState { ), ); } + + void _observePopToPlacesListScreen() { + ref.listen( + choosePlaceViewStateProvider.select((state) => state.popToPlaceList), + (_, next) { + AppRoute.popTo(context, AppRoute.pathPlacesList); + _showPlaceAddedPrompt( + context, + widget.location.latitude, + widget.location.longitude, + _textController.text, + ); + }); + } + + void _showPlaceAddedPrompt( + BuildContext context, + double lat, + double lng, + String placeName, + ) { + showDialog( + context: context, + barrierDismissible: false, + builder: (context) { + return AlertDialog( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + AspectRatio( + aspectRatio: 1.77, + child: _googleMapView(lat, lng), + ), + const SizedBox(height: 24), + Text( + context.l10n.choose_place_prompt_added_title_text(placeName), + style: AppTextStyle.header1 + .copyWith(color: context.colorScheme.textPrimary), + textAlign: TextAlign.center, + ), + const SizedBox(height: 14), + Text( + context.l10n.choose_place_prompt_sub_title_text, + style: AppTextStyle.body1 + .copyWith(color: context.colorScheme.textSecondary), + textAlign: TextAlign.center, + ), + const SizedBox(height: 24), + PrimaryButton( + context.l10n.choose_place_prompt_got_it_btn_text, + onPressed: () { + Navigator.of(context).pop(); + }, + ), + const SizedBox(height: 24), + ], + ), + ); + }, + ); + } + + Widget _googleMapView(double lat, double lng) { + final cameraPosition = + CameraPosition(target: LatLng(lat, lng), zoom: defaultCameraZoom); + return Stack( + alignment: Alignment.center, + children: [ + GoogleMap( + initialCameraPosition: cameraPosition, + scrollGesturesEnabled: false, + rotateGesturesEnabled: false, + compassEnabled: false, + zoomControlsEnabled: false, + tiltGesturesEnabled: false, + myLocationButtonEnabled: false, + mapToolbarEnabled: false, + ), + _locateMarkerView() + ], + ); + } + + Widget _locateMarkerView() { + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: context.colorScheme.onPrimary, + ), + child: Padding( + padding: const EdgeInsets.all(4), + child: SvgPicture.asset( + Assets.images.icLocationFeedIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.primary, + BlendMode.srcATop, + ), + ), + ), + ); + } } diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart index 9357fb28..5ed3d84c 100644 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart @@ -49,6 +49,7 @@ class ChoosePlaceNameViewNotifier extends StateNotifier { void onTapAddPlaceBtn(String value) async { try { + state = state.copyWith(addingPlace: true); final members = await spaceService.getMemberBySpaceId(_spaceId!); final memberIds = members.map((member) => member.id).toList(); @@ -60,7 +61,8 @@ class ChoosePlaceNameViewNotifier extends StateNotifier { _currentUser!.id, memberIds, ); - + state = + state.copyWith(popToPlaceList: DateTime.now(), addingPlace: false); } catch (error, stack) { state = state.copyWith(addingPlace: false, error: error); logger.e( @@ -74,9 +76,11 @@ class ChoosePlaceNameViewNotifier extends StateNotifier { @freezed class ChoosePlaceViewState with _$ChoosePlaceViewState { - const factory ChoosePlaceViewState( - {@Default(false) addingPlace, - List? suggestions, - String? placeName, - Object? error}) = _ChoosePlaceViewState; + const factory ChoosePlaceViewState({ + @Default(false) addingPlace, + List? suggestions, + String? placeName, + Object? error, + DateTime? popToPlaceList, + }) = _ChoosePlaceViewState; } diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart deleted file mode 100644 index b7b88292..00000000 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart +++ /dev/null @@ -1,208 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'choose_place_name_view_model.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -/// @nodoc -mixin _$ChoosePlaceViewState { - dynamic get addingPlace => throw _privateConstructorUsedError; - List? get suggestions => throw _privateConstructorUsedError; - String? get placeName => throw _privateConstructorUsedError; - Object? get error => throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $ChoosePlaceViewStateCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $ChoosePlaceViewStateCopyWith<$Res> { - factory $ChoosePlaceViewStateCopyWith(ChoosePlaceViewState value, - $Res Function(ChoosePlaceViewState) then) = - _$ChoosePlaceViewStateCopyWithImpl<$Res, ChoosePlaceViewState>; - @useResult - $Res call( - {dynamic addingPlace, - List? suggestions, - String? placeName, - Object? error}); -} - -/// @nodoc -class _$ChoosePlaceViewStateCopyWithImpl<$Res, - $Val extends ChoosePlaceViewState> - implements $ChoosePlaceViewStateCopyWith<$Res> { - _$ChoosePlaceViewStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? addingPlace = freezed, - Object? suggestions = freezed, - Object? placeName = freezed, - Object? error = freezed, - }) { - return _then(_value.copyWith( - addingPlace: freezed == addingPlace - ? _value.addingPlace - : addingPlace // ignore: cast_nullable_to_non_nullable - as dynamic, - suggestions: freezed == suggestions - ? _value.suggestions - : suggestions // ignore: cast_nullable_to_non_nullable - as List?, - placeName: freezed == placeName - ? _value.placeName - : placeName // ignore: cast_nullable_to_non_nullable - as String?, - error: freezed == error ? _value.error : error, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$ChoosePlaceViewStateImplCopyWith<$Res> - implements $ChoosePlaceViewStateCopyWith<$Res> { - factory _$$ChoosePlaceViewStateImplCopyWith(_$ChoosePlaceViewStateImpl value, - $Res Function(_$ChoosePlaceViewStateImpl) then) = - __$$ChoosePlaceViewStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {dynamic addingPlace, - List? suggestions, - String? placeName, - Object? error}); -} - -/// @nodoc -class __$$ChoosePlaceViewStateImplCopyWithImpl<$Res> - extends _$ChoosePlaceViewStateCopyWithImpl<$Res, _$ChoosePlaceViewStateImpl> - implements _$$ChoosePlaceViewStateImplCopyWith<$Res> { - __$$ChoosePlaceViewStateImplCopyWithImpl(_$ChoosePlaceViewStateImpl _value, - $Res Function(_$ChoosePlaceViewStateImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? addingPlace = freezed, - Object? suggestions = freezed, - Object? placeName = freezed, - Object? error = freezed, - }) { - return _then(_$ChoosePlaceViewStateImpl( - addingPlace: freezed == addingPlace ? _value.addingPlace! : addingPlace, - suggestions: freezed == suggestions - ? _value._suggestions - : suggestions // ignore: cast_nullable_to_non_nullable - as List?, - placeName: freezed == placeName - ? _value.placeName - : placeName // ignore: cast_nullable_to_non_nullable - as String?, - error: freezed == error ? _value.error : error, - )); - } -} - -/// @nodoc - -class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { - const _$ChoosePlaceViewStateImpl( - {this.addingPlace = false, - final List? suggestions, - this.placeName, - this.error}) - : _suggestions = suggestions; - - @override - @JsonKey() - final dynamic addingPlace; - final List? _suggestions; - @override - List? get suggestions { - final value = _suggestions; - if (value == null) return null; - if (_suggestions is EqualUnmodifiableListView) return _suggestions; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(value); - } - - @override - final String? placeName; - @override - final Object? error; - - @override - String toString() { - return 'ChoosePlaceViewState(addingPlace: $addingPlace, suggestions: $suggestions, placeName: $placeName, error: $error)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$ChoosePlaceViewStateImpl && - const DeepCollectionEquality() - .equals(other.addingPlace, addingPlace) && - const DeepCollectionEquality() - .equals(other._suggestions, _suggestions) && - (identical(other.placeName, placeName) || - other.placeName == placeName) && - const DeepCollectionEquality().equals(other.error, error)); - } - - @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(addingPlace), - const DeepCollectionEquality().hash(_suggestions), - placeName, - const DeepCollectionEquality().hash(error)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$ChoosePlaceViewStateImplCopyWith<_$ChoosePlaceViewStateImpl> - get copyWith => - __$$ChoosePlaceViewStateImplCopyWithImpl<_$ChoosePlaceViewStateImpl>( - this, _$identity); -} - -abstract class _ChoosePlaceViewState implements ChoosePlaceViewState { - const factory _ChoosePlaceViewState( - {final dynamic addingPlace, - final List? suggestions, - final String? placeName, - final Object? error}) = _$ChoosePlaceViewStateImpl; - - @override - dynamic get addingPlace; - @override - List? get suggestions; - @override - String? get placeName; - @override - Object? get error; - @override - @JsonKey(ignore: true) - _$$ChoosePlaceViewStateImplCopyWith<_$ChoosePlaceViewStateImpl> - get copyWith => throw _privateConstructorUsedError; -} diff --git a/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart b/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart deleted file mode 100644 index b7518e6c..00000000 --- a/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart +++ /dev/null @@ -1,491 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'places_list_view_model.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -/// @nodoc -mixin _$PlacesListState { - bool get loading => throw _privateConstructorUsedError; - bool get deletingPlaces => throw _privateConstructorUsedError; - String? get spaceId => throw _privateConstructorUsedError; - DateTime? get showDeletePlaceDialog => throw _privateConstructorUsedError; - ApiPlace? get placesToDelete => throw _privateConstructorUsedError; - ApiUser? get currentUser => throw _privateConstructorUsedError; - List get places => throw _privateConstructorUsedError; - List get suggestions => throw _privateConstructorUsedError; - Object? get error => throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $PlacesListStateCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $PlacesListStateCopyWith<$Res> { - factory $PlacesListStateCopyWith( - PlacesListState value, $Res Function(PlacesListState) then) = - _$PlacesListStateCopyWithImpl<$Res, PlacesListState>; - @useResult - $Res call( - {bool loading, - bool deletingPlaces, - String? spaceId, - DateTime? showDeletePlaceDialog, - ApiPlace? placesToDelete, - ApiUser? currentUser, - List places, - List suggestions, - Object? error}); - - $ApiPlaceCopyWith<$Res>? get placesToDelete; - $ApiUserCopyWith<$Res>? get currentUser; -} - -/// @nodoc -class _$PlacesListStateCopyWithImpl<$Res, $Val extends PlacesListState> - implements $PlacesListStateCopyWith<$Res> { - _$PlacesListStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? loading = null, - Object? deletingPlaces = null, - Object? spaceId = freezed, - Object? showDeletePlaceDialog = freezed, - Object? placesToDelete = freezed, - Object? currentUser = freezed, - Object? places = null, - Object? suggestions = null, - Object? error = freezed, - }) { - return _then(_value.copyWith( - loading: null == loading - ? _value.loading - : loading // ignore: cast_nullable_to_non_nullable - as bool, - deletingPlaces: null == deletingPlaces - ? _value.deletingPlaces - : deletingPlaces // ignore: cast_nullable_to_non_nullable - as bool, - spaceId: freezed == spaceId - ? _value.spaceId - : spaceId // ignore: cast_nullable_to_non_nullable - as String?, - showDeletePlaceDialog: freezed == showDeletePlaceDialog - ? _value.showDeletePlaceDialog - : showDeletePlaceDialog // ignore: cast_nullable_to_non_nullable - as DateTime?, - placesToDelete: freezed == placesToDelete - ? _value.placesToDelete - : placesToDelete // ignore: cast_nullable_to_non_nullable - as ApiPlace?, - currentUser: freezed == currentUser - ? _value.currentUser - : currentUser // ignore: cast_nullable_to_non_nullable - as ApiUser?, - places: null == places - ? _value.places - : places // ignore: cast_nullable_to_non_nullable - as List, - suggestions: null == suggestions - ? _value.suggestions - : suggestions // ignore: cast_nullable_to_non_nullable - as List, - error: freezed == error ? _value.error : error, - ) as $Val); - } - - @override - @pragma('vm:prefer-inline') - $ApiPlaceCopyWith<$Res>? get placesToDelete { - if (_value.placesToDelete == null) { - return null; - } - - return $ApiPlaceCopyWith<$Res>(_value.placesToDelete!, (value) { - return _then(_value.copyWith(placesToDelete: value) as $Val); - }); - } - - @override - @pragma('vm:prefer-inline') - $ApiUserCopyWith<$Res>? get currentUser { - if (_value.currentUser == null) { - return null; - } - - return $ApiUserCopyWith<$Res>(_value.currentUser!, (value) { - return _then(_value.copyWith(currentUser: value) as $Val); - }); - } -} - -/// @nodoc -abstract class _$$PlacesListStateImplCopyWith<$Res> - implements $PlacesListStateCopyWith<$Res> { - factory _$$PlacesListStateImplCopyWith(_$PlacesListStateImpl value, - $Res Function(_$PlacesListStateImpl) then) = - __$$PlacesListStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {bool loading, - bool deletingPlaces, - String? spaceId, - DateTime? showDeletePlaceDialog, - ApiPlace? placesToDelete, - ApiUser? currentUser, - List places, - List suggestions, - Object? error}); - - @override - $ApiPlaceCopyWith<$Res>? get placesToDelete; - @override - $ApiUserCopyWith<$Res>? get currentUser; -} - -/// @nodoc -class __$$PlacesListStateImplCopyWithImpl<$Res> - extends _$PlacesListStateCopyWithImpl<$Res, _$PlacesListStateImpl> - implements _$$PlacesListStateImplCopyWith<$Res> { - __$$PlacesListStateImplCopyWithImpl( - _$PlacesListStateImpl _value, $Res Function(_$PlacesListStateImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? loading = null, - Object? deletingPlaces = null, - Object? spaceId = freezed, - Object? showDeletePlaceDialog = freezed, - Object? placesToDelete = freezed, - Object? currentUser = freezed, - Object? places = null, - Object? suggestions = null, - Object? error = freezed, - }) { - return _then(_$PlacesListStateImpl( - loading: null == loading - ? _value.loading - : loading // ignore: cast_nullable_to_non_nullable - as bool, - deletingPlaces: null == deletingPlaces - ? _value.deletingPlaces - : deletingPlaces // ignore: cast_nullable_to_non_nullable - as bool, - spaceId: freezed == spaceId - ? _value.spaceId - : spaceId // ignore: cast_nullable_to_non_nullable - as String?, - showDeletePlaceDialog: freezed == showDeletePlaceDialog - ? _value.showDeletePlaceDialog - : showDeletePlaceDialog // ignore: cast_nullable_to_non_nullable - as DateTime?, - placesToDelete: freezed == placesToDelete - ? _value.placesToDelete - : placesToDelete // ignore: cast_nullable_to_non_nullable - as ApiPlace?, - currentUser: freezed == currentUser - ? _value.currentUser - : currentUser // ignore: cast_nullable_to_non_nullable - as ApiUser?, - places: null == places - ? _value._places - : places // ignore: cast_nullable_to_non_nullable - as List, - suggestions: null == suggestions - ? _value._suggestions - : suggestions // ignore: cast_nullable_to_non_nullable - as List, - error: freezed == error ? _value.error : error, - )); - } -} - -/// @nodoc - -class _$PlacesListStateImpl implements _PlacesListState { - const _$PlacesListStateImpl( - {this.loading = false, - this.deletingPlaces = false, - this.spaceId, - this.showDeletePlaceDialog, - this.placesToDelete, - this.currentUser, - final List places = const [], - final List suggestions = const [], - this.error}) - : _places = places, - _suggestions = suggestions; - - @override - @JsonKey() - final bool loading; - @override - @JsonKey() - final bool deletingPlaces; - @override - final String? spaceId; - @override - final DateTime? showDeletePlaceDialog; - @override - final ApiPlace? placesToDelete; - @override - final ApiUser? currentUser; - final List _places; - @override - @JsonKey() - List get places { - if (_places is EqualUnmodifiableListView) return _places; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_places); - } - - final List _suggestions; - @override - @JsonKey() - List get suggestions { - if (_suggestions is EqualUnmodifiableListView) return _suggestions; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_suggestions); - } - - @override - final Object? error; - - @override - String toString() { - return 'PlacesListState(loading: $loading, deletingPlaces: $deletingPlaces, spaceId: $spaceId, showDeletePlaceDialog: $showDeletePlaceDialog, placesToDelete: $placesToDelete, currentUser: $currentUser, places: $places, suggestions: $suggestions, error: $error)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$PlacesListStateImpl && - (identical(other.loading, loading) || other.loading == loading) && - (identical(other.deletingPlaces, deletingPlaces) || - other.deletingPlaces == deletingPlaces) && - (identical(other.spaceId, spaceId) || other.spaceId == spaceId) && - (identical(other.showDeletePlaceDialog, showDeletePlaceDialog) || - other.showDeletePlaceDialog == showDeletePlaceDialog) && - (identical(other.placesToDelete, placesToDelete) || - other.placesToDelete == placesToDelete) && - (identical(other.currentUser, currentUser) || - other.currentUser == currentUser) && - const DeepCollectionEquality().equals(other._places, _places) && - const DeepCollectionEquality() - .equals(other._suggestions, _suggestions) && - const DeepCollectionEquality().equals(other.error, error)); - } - - @override - int get hashCode => Object.hash( - runtimeType, - loading, - deletingPlaces, - spaceId, - showDeletePlaceDialog, - placesToDelete, - currentUser, - const DeepCollectionEquality().hash(_places), - const DeepCollectionEquality().hash(_suggestions), - const DeepCollectionEquality().hash(error)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$PlacesListStateImplCopyWith<_$PlacesListStateImpl> get copyWith => - __$$PlacesListStateImplCopyWithImpl<_$PlacesListStateImpl>( - this, _$identity); -} - -abstract class _PlacesListState implements PlacesListState { - const factory _PlacesListState( - {final bool loading, - final bool deletingPlaces, - final String? spaceId, - final DateTime? showDeletePlaceDialog, - final ApiPlace? placesToDelete, - final ApiUser? currentUser, - final List places, - final List suggestions, - final Object? error}) = _$PlacesListStateImpl; - - @override - bool get loading; - @override - bool get deletingPlaces; - @override - String? get spaceId; - @override - DateTime? get showDeletePlaceDialog; - @override - ApiPlace? get placesToDelete; - @override - ApiUser? get currentUser; - @override - List get places; - @override - List get suggestions; - @override - Object? get error; - @override - @JsonKey(ignore: true) - _$$PlacesListStateImplCopyWith<_$PlacesListStateImpl> get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -mixin _$Suggestions { - String get name => throw _privateConstructorUsedError; - String get icon => throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $SuggestionsCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $SuggestionsCopyWith<$Res> { - factory $SuggestionsCopyWith( - Suggestions value, $Res Function(Suggestions) then) = - _$SuggestionsCopyWithImpl<$Res, Suggestions>; - @useResult - $Res call({String name, String icon}); -} - -/// @nodoc -class _$SuggestionsCopyWithImpl<$Res, $Val extends Suggestions> - implements $SuggestionsCopyWith<$Res> { - _$SuggestionsCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? name = null, - Object? icon = null, - }) { - return _then(_value.copyWith( - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - icon: null == icon - ? _value.icon - : icon // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$SuggestionsImplCopyWith<$Res> - implements $SuggestionsCopyWith<$Res> { - factory _$$SuggestionsImplCopyWith( - _$SuggestionsImpl value, $Res Function(_$SuggestionsImpl) then) = - __$$SuggestionsImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({String name, String icon}); -} - -/// @nodoc -class __$$SuggestionsImplCopyWithImpl<$Res> - extends _$SuggestionsCopyWithImpl<$Res, _$SuggestionsImpl> - implements _$$SuggestionsImplCopyWith<$Res> { - __$$SuggestionsImplCopyWithImpl( - _$SuggestionsImpl _value, $Res Function(_$SuggestionsImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? name = null, - Object? icon = null, - }) { - return _then(_$SuggestionsImpl( - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - icon: null == icon - ? _value.icon - : icon // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc - -class _$SuggestionsImpl implements _Suggestions { - const _$SuggestionsImpl({required this.name, required this.icon}); - - @override - final String name; - @override - final String icon; - - @override - String toString() { - return 'Suggestions(name: $name, icon: $icon)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$SuggestionsImpl && - (identical(other.name, name) || other.name == name) && - (identical(other.icon, icon) || other.icon == icon)); - } - - @override - int get hashCode => Object.hash(runtimeType, name, icon); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$SuggestionsImplCopyWith<_$SuggestionsImpl> get copyWith => - __$$SuggestionsImplCopyWithImpl<_$SuggestionsImpl>(this, _$identity); -} - -abstract class _Suggestions implements Suggestions { - const factory _Suggestions( - {required final String name, - required final String icon}) = _$SuggestionsImpl; - - @override - String get name; - @override - String get icon; - @override - @JsonKey(ignore: true) - _$$SuggestionsImplCopyWith<_$SuggestionsImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/app/lib/ui/flow/home/map/map_view_model.freezed.dart b/app/lib/ui/flow/home/map/map_view_model.freezed.dart deleted file mode 100644 index ce3f33ca..00000000 --- a/app/lib/ui/flow/home/map/map_view_model.freezed.dart +++ /dev/null @@ -1,572 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'map_view_model.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -/// @nodoc -mixin _$MapViewState { - dynamic get loading => throw _privateConstructorUsedError; - bool get fetchingInviteCode => throw _privateConstructorUsedError; - List get userInfo => throw _privateConstructorUsedError; - List get places => throw _privateConstructorUsedError; - List get markers => throw _privateConstructorUsedError; - ApiUserInfo? get selectedUser => throw _privateConstructorUsedError; - CameraPosition? get defaultPosition => throw _privateConstructorUsedError; - String get spaceInvitationCode => throw _privateConstructorUsedError; - Object? get error => throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $MapViewStateCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $MapViewStateCopyWith<$Res> { - factory $MapViewStateCopyWith( - MapViewState value, $Res Function(MapViewState) then) = - _$MapViewStateCopyWithImpl<$Res, MapViewState>; - @useResult - $Res call( - {dynamic loading, - bool fetchingInviteCode, - List userInfo, - List places, - List markers, - ApiUserInfo? selectedUser, - CameraPosition? defaultPosition, - String spaceInvitationCode, - Object? error}); - - $ApiUserInfoCopyWith<$Res>? get selectedUser; -} - -/// @nodoc -class _$MapViewStateCopyWithImpl<$Res, $Val extends MapViewState> - implements $MapViewStateCopyWith<$Res> { - _$MapViewStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? loading = freezed, - Object? fetchingInviteCode = null, - Object? userInfo = null, - Object? places = null, - Object? markers = null, - Object? selectedUser = freezed, - Object? defaultPosition = freezed, - Object? spaceInvitationCode = null, - Object? error = freezed, - }) { - return _then(_value.copyWith( - loading: freezed == loading - ? _value.loading - : loading // ignore: cast_nullable_to_non_nullable - as dynamic, - fetchingInviteCode: null == fetchingInviteCode - ? _value.fetchingInviteCode - : fetchingInviteCode // ignore: cast_nullable_to_non_nullable - as bool, - userInfo: null == userInfo - ? _value.userInfo - : userInfo // ignore: cast_nullable_to_non_nullable - as List, - places: null == places - ? _value.places - : places // ignore: cast_nullable_to_non_nullable - as List, - markers: null == markers - ? _value.markers - : markers // ignore: cast_nullable_to_non_nullable - as List, - selectedUser: freezed == selectedUser - ? _value.selectedUser - : selectedUser // ignore: cast_nullable_to_non_nullable - as ApiUserInfo?, - defaultPosition: freezed == defaultPosition - ? _value.defaultPosition - : defaultPosition // ignore: cast_nullable_to_non_nullable - as CameraPosition?, - spaceInvitationCode: null == spaceInvitationCode - ? _value.spaceInvitationCode - : spaceInvitationCode // ignore: cast_nullable_to_non_nullable - as String, - error: freezed == error ? _value.error : error, - ) as $Val); - } - - @override - @pragma('vm:prefer-inline') - $ApiUserInfoCopyWith<$Res>? get selectedUser { - if (_value.selectedUser == null) { - return null; - } - - return $ApiUserInfoCopyWith<$Res>(_value.selectedUser!, (value) { - return _then(_value.copyWith(selectedUser: value) as $Val); - }); - } -} - -/// @nodoc -abstract class _$$MapViewStateImplCopyWith<$Res> - implements $MapViewStateCopyWith<$Res> { - factory _$$MapViewStateImplCopyWith( - _$MapViewStateImpl value, $Res Function(_$MapViewStateImpl) then) = - __$$MapViewStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {dynamic loading, - bool fetchingInviteCode, - List userInfo, - List places, - List markers, - ApiUserInfo? selectedUser, - CameraPosition? defaultPosition, - String spaceInvitationCode, - Object? error}); - - @override - $ApiUserInfoCopyWith<$Res>? get selectedUser; -} - -/// @nodoc -class __$$MapViewStateImplCopyWithImpl<$Res> - extends _$MapViewStateCopyWithImpl<$Res, _$MapViewStateImpl> - implements _$$MapViewStateImplCopyWith<$Res> { - __$$MapViewStateImplCopyWithImpl( - _$MapViewStateImpl _value, $Res Function(_$MapViewStateImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? loading = freezed, - Object? fetchingInviteCode = null, - Object? userInfo = null, - Object? places = null, - Object? markers = null, - Object? selectedUser = freezed, - Object? defaultPosition = freezed, - Object? spaceInvitationCode = null, - Object? error = freezed, - }) { - return _then(_$MapViewStateImpl( - loading: freezed == loading ? _value.loading! : loading, - fetchingInviteCode: null == fetchingInviteCode - ? _value.fetchingInviteCode - : fetchingInviteCode // ignore: cast_nullable_to_non_nullable - as bool, - userInfo: null == userInfo - ? _value._userInfo - : userInfo // ignore: cast_nullable_to_non_nullable - as List, - places: null == places - ? _value._places - : places // ignore: cast_nullable_to_non_nullable - as List, - markers: null == markers - ? _value._markers - : markers // ignore: cast_nullable_to_non_nullable - as List, - selectedUser: freezed == selectedUser - ? _value.selectedUser - : selectedUser // ignore: cast_nullable_to_non_nullable - as ApiUserInfo?, - defaultPosition: freezed == defaultPosition - ? _value.defaultPosition - : defaultPosition // ignore: cast_nullable_to_non_nullable - as CameraPosition?, - spaceInvitationCode: null == spaceInvitationCode - ? _value.spaceInvitationCode - : spaceInvitationCode // ignore: cast_nullable_to_non_nullable - as String, - error: freezed == error ? _value.error : error, - )); - } -} - -/// @nodoc - -class _$MapViewStateImpl implements _MapViewState { - const _$MapViewStateImpl( - {this.loading = false, - this.fetchingInviteCode = false, - final List userInfo = const [], - final List places = const [], - final List markers = const [], - this.selectedUser, - this.defaultPosition, - this.spaceInvitationCode = '', - this.error}) - : _userInfo = userInfo, - _places = places, - _markers = markers; - - @override - @JsonKey() - final dynamic loading; - @override - @JsonKey() - final bool fetchingInviteCode; - final List _userInfo; - @override - @JsonKey() - List get userInfo { - if (_userInfo is EqualUnmodifiableListView) return _userInfo; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_userInfo); - } - - final List _places; - @override - @JsonKey() - List get places { - if (_places is EqualUnmodifiableListView) return _places; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_places); - } - - final List _markers; - @override - @JsonKey() - List get markers { - if (_markers is EqualUnmodifiableListView) return _markers; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_markers); - } - - @override - final ApiUserInfo? selectedUser; - @override - final CameraPosition? defaultPosition; - @override - @JsonKey() - final String spaceInvitationCode; - @override - final Object? error; - - @override - String toString() { - return 'MapViewState(loading: $loading, fetchingInviteCode: $fetchingInviteCode, userInfo: $userInfo, places: $places, markers: $markers, selectedUser: $selectedUser, defaultPosition: $defaultPosition, spaceInvitationCode: $spaceInvitationCode, error: $error)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$MapViewStateImpl && - const DeepCollectionEquality().equals(other.loading, loading) && - (identical(other.fetchingInviteCode, fetchingInviteCode) || - other.fetchingInviteCode == fetchingInviteCode) && - const DeepCollectionEquality().equals(other._userInfo, _userInfo) && - const DeepCollectionEquality().equals(other._places, _places) && - const DeepCollectionEquality().equals(other._markers, _markers) && - (identical(other.selectedUser, selectedUser) || - other.selectedUser == selectedUser) && - (identical(other.defaultPosition, defaultPosition) || - other.defaultPosition == defaultPosition) && - (identical(other.spaceInvitationCode, spaceInvitationCode) || - other.spaceInvitationCode == spaceInvitationCode) && - const DeepCollectionEquality().equals(other.error, error)); - } - - @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(loading), - fetchingInviteCode, - const DeepCollectionEquality().hash(_userInfo), - const DeepCollectionEquality().hash(_places), - const DeepCollectionEquality().hash(_markers), - selectedUser, - defaultPosition, - spaceInvitationCode, - const DeepCollectionEquality().hash(error)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$MapViewStateImplCopyWith<_$MapViewStateImpl> get copyWith => - __$$MapViewStateImplCopyWithImpl<_$MapViewStateImpl>(this, _$identity); -} - -abstract class _MapViewState implements MapViewState { - const factory _MapViewState( - {final dynamic loading, - final bool fetchingInviteCode, - final List userInfo, - final List places, - final List markers, - final ApiUserInfo? selectedUser, - final CameraPosition? defaultPosition, - final String spaceInvitationCode, - final Object? error}) = _$MapViewStateImpl; - - @override - dynamic get loading; - @override - bool get fetchingInviteCode; - @override - List get userInfo; - @override - List get places; - @override - List get markers; - @override - ApiUserInfo? get selectedUser; - @override - CameraPosition? get defaultPosition; - @override - String get spaceInvitationCode; - @override - Object? get error; - @override - @JsonKey(ignore: true) - _$$MapViewStateImplCopyWith<_$MapViewStateImpl> get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -mixin _$UserMarker { - String get userId => throw _privateConstructorUsedError; - String get userName => throw _privateConstructorUsedError; - ui.Image? get imageUrl => throw _privateConstructorUsedError; - double get latitude => throw _privateConstructorUsedError; - double get longitude => throw _privateConstructorUsedError; - bool get isSelected => throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $UserMarkerCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $UserMarkerCopyWith<$Res> { - factory $UserMarkerCopyWith( - UserMarker value, $Res Function(UserMarker) then) = - _$UserMarkerCopyWithImpl<$Res, UserMarker>; - @useResult - $Res call( - {String userId, - String userName, - ui.Image? imageUrl, - double latitude, - double longitude, - bool isSelected}); -} - -/// @nodoc -class _$UserMarkerCopyWithImpl<$Res, $Val extends UserMarker> - implements $UserMarkerCopyWith<$Res> { - _$UserMarkerCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? userId = null, - Object? userName = null, - Object? imageUrl = freezed, - Object? latitude = null, - Object? longitude = null, - Object? isSelected = null, - }) { - return _then(_value.copyWith( - userId: null == userId - ? _value.userId - : userId // ignore: cast_nullable_to_non_nullable - as String, - userName: null == userName - ? _value.userName - : userName // ignore: cast_nullable_to_non_nullable - as String, - imageUrl: freezed == imageUrl - ? _value.imageUrl - : imageUrl // ignore: cast_nullable_to_non_nullable - as ui.Image?, - latitude: null == latitude - ? _value.latitude - : latitude // ignore: cast_nullable_to_non_nullable - as double, - longitude: null == longitude - ? _value.longitude - : longitude // ignore: cast_nullable_to_non_nullable - as double, - isSelected: null == isSelected - ? _value.isSelected - : isSelected // ignore: cast_nullable_to_non_nullable - as bool, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$UserMarkerImplCopyWith<$Res> - implements $UserMarkerCopyWith<$Res> { - factory _$$UserMarkerImplCopyWith( - _$UserMarkerImpl value, $Res Function(_$UserMarkerImpl) then) = - __$$UserMarkerImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String userId, - String userName, - ui.Image? imageUrl, - double latitude, - double longitude, - bool isSelected}); -} - -/// @nodoc -class __$$UserMarkerImplCopyWithImpl<$Res> - extends _$UserMarkerCopyWithImpl<$Res, _$UserMarkerImpl> - implements _$$UserMarkerImplCopyWith<$Res> { - __$$UserMarkerImplCopyWithImpl( - _$UserMarkerImpl _value, $Res Function(_$UserMarkerImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? userId = null, - Object? userName = null, - Object? imageUrl = freezed, - Object? latitude = null, - Object? longitude = null, - Object? isSelected = null, - }) { - return _then(_$UserMarkerImpl( - userId: null == userId - ? _value.userId - : userId // ignore: cast_nullable_to_non_nullable - as String, - userName: null == userName - ? _value.userName - : userName // ignore: cast_nullable_to_non_nullable - as String, - imageUrl: freezed == imageUrl - ? _value.imageUrl - : imageUrl // ignore: cast_nullable_to_non_nullable - as ui.Image?, - latitude: null == latitude - ? _value.latitude - : latitude // ignore: cast_nullable_to_non_nullable - as double, - longitude: null == longitude - ? _value.longitude - : longitude // ignore: cast_nullable_to_non_nullable - as double, - isSelected: null == isSelected - ? _value.isSelected - : isSelected // ignore: cast_nullable_to_non_nullable - as bool, - )); - } -} - -/// @nodoc - -class _$UserMarkerImpl implements _UserMarker { - const _$UserMarkerImpl( - {required this.userId, - required this.userName, - required this.imageUrl, - required this.latitude, - required this.longitude, - required this.isSelected}); - - @override - final String userId; - @override - final String userName; - @override - final ui.Image? imageUrl; - @override - final double latitude; - @override - final double longitude; - @override - final bool isSelected; - - @override - String toString() { - return 'UserMarker(userId: $userId, userName: $userName, imageUrl: $imageUrl, latitude: $latitude, longitude: $longitude, isSelected: $isSelected)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$UserMarkerImpl && - (identical(other.userId, userId) || other.userId == userId) && - (identical(other.userName, userName) || - other.userName == userName) && - (identical(other.imageUrl, imageUrl) || - other.imageUrl == imageUrl) && - (identical(other.latitude, latitude) || - other.latitude == latitude) && - (identical(other.longitude, longitude) || - other.longitude == longitude) && - (identical(other.isSelected, isSelected) || - other.isSelected == isSelected)); - } - - @override - int get hashCode => Object.hash( - runtimeType, userId, userName, imageUrl, latitude, longitude, isSelected); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$UserMarkerImplCopyWith<_$UserMarkerImpl> get copyWith => - __$$UserMarkerImplCopyWithImpl<_$UserMarkerImpl>(this, _$identity); -} - -abstract class _UserMarker implements UserMarker { - const factory _UserMarker( - {required final String userId, - required final String userName, - required final ui.Image? imageUrl, - required final double latitude, - required final double longitude, - required final bool isSelected}) = _$UserMarkerImpl; - - @override - String get userId; - @override - String get userName; - @override - ui.Image? get imageUrl; - @override - double get latitude; - @override - double get longitude; - @override - bool get isSelected; - @override - @JsonKey(ignore: true) - _$$UserMarkerImplCopyWith<_$UserMarkerImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/data/lib/api/place/api_place.dart b/data/lib/api/place/api_place.dart index e7b0c785..1a91e4f8 100644 --- a/data/lib/api/place/api_place.dart +++ b/data/lib/api/place/api_place.dart @@ -4,6 +4,8 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'api_place.freezed.dart'; part 'api_place.g.dart'; +const geofenceDefaultPlaceRadius = 200.0; + @freezed class ApiPlace with _$ApiPlace { const ApiPlace._(); diff --git a/data/lib/service/place_service.dart b/data/lib/service/place_service.dart index 3e6ac5a1..4598f19d 100644 --- a/data/lib/service/place_service.dart +++ b/data/lib/service/place_service.dart @@ -22,6 +22,12 @@ class PlaceService { CollectionReference spacePlacesRef(String spaceId) => _spaceRef.doc(spaceId).collection('space_places'); + CollectionReference spacePlacesSettingsRef(String spaceId, String placeId) { + return spacePlacesRef(spaceId) + .doc(placeId) + .collection('place_settings_by_members'); + } + Stream> getAllPlacesStream(String spaceId) { return spacePlacesRef(spaceId).snapshots().map((snapshot) => snapshot.docs .map((doc) => ApiPlace.fromJson(doc.data() as Map)) @@ -40,7 +46,37 @@ class PlaceService { String createdBy, List spaceMemberIds, ) async { + final placeDoc = spacePlacesRef(spaceId).doc(); + print('XXX place doc:${placeDoc.id}'); + final place = ApiPlace( + id: placeDoc.id, + space_id: spaceId, + created_by: createdBy, + latitude: latitude, + longitude: longitude, + radius: geofenceDefaultPlaceRadius, + name: name, + created_at: DateTime.now(), + ); + print('XXX places:${place}'); + await placeDoc.set(place.toJson()); + print('XXX place after set'); + final settings = spaceMemberIds.map((memberId) { + final filterIds = spaceMemberIds.where((id) => id != memberId).toList(); + return ApiPlaceMemberSetting( + user_id: memberId, + place_id: place.id, + alert_enabled: true, + arrival_alert_for: filterIds, + leave_alert_for: filterIds, + ); + }).toList(); + for (final setting in settings) { + await spacePlacesSettingsRef(spaceId, place.id) + .doc(setting.user_id) + .set(setting.toJson()); + } } } From c3b71d72087813c8e7fcf4d340c87eebe0206ed3 Mon Sep 17 00:00:00 2001 From: kaushik Date: Tue, 25 Jun 2024 14:31:36 +0530 Subject: [PATCH 23/65] Fix add places --- .../add_new_place_view_model.freezed.dart | 145 +++++ .../choose_place_name_view_model.freezed.dart | 230 +++++++ .../places_list_view_model.freezed.dart | 491 +++++++++++++++ .../flow/home/map/map_view_model.freezed.dart | 572 ++++++++++++++++++ 4 files changed, 1438 insertions(+) create mode 100644 app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart create mode 100644 app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart create mode 100644 app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart create mode 100644 app/lib/ui/flow/home/map/map_view_model.freezed.dart diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart new file mode 100644 index 00000000..37e74690 --- /dev/null +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart @@ -0,0 +1,145 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'add_new_place_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$AddNewPlaceState { + dynamic get loading => throw _privateConstructorUsedError; + Object? get error => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $AddNewPlaceStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AddNewPlaceStateCopyWith<$Res> { + factory $AddNewPlaceStateCopyWith( + AddNewPlaceState value, $Res Function(AddNewPlaceState) then) = + _$AddNewPlaceStateCopyWithImpl<$Res, AddNewPlaceState>; + @useResult + $Res call({dynamic loading, Object? error}); +} + +/// @nodoc +class _$AddNewPlaceStateCopyWithImpl<$Res, $Val extends AddNewPlaceState> + implements $AddNewPlaceStateCopyWith<$Res> { + _$AddNewPlaceStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = freezed, + Object? error = freezed, + }) { + return _then(_value.copyWith( + loading: freezed == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as dynamic, + error: freezed == error ? _value.error : error, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AddNewPlaceStateImplCopyWith<$Res> + implements $AddNewPlaceStateCopyWith<$Res> { + factory _$$AddNewPlaceStateImplCopyWith(_$AddNewPlaceStateImpl value, + $Res Function(_$AddNewPlaceStateImpl) then) = + __$$AddNewPlaceStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({dynamic loading, Object? error}); +} + +/// @nodoc +class __$$AddNewPlaceStateImplCopyWithImpl<$Res> + extends _$AddNewPlaceStateCopyWithImpl<$Res, _$AddNewPlaceStateImpl> + implements _$$AddNewPlaceStateImplCopyWith<$Res> { + __$$AddNewPlaceStateImplCopyWithImpl(_$AddNewPlaceStateImpl _value, + $Res Function(_$AddNewPlaceStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = freezed, + Object? error = freezed, + }) { + return _then(_$AddNewPlaceStateImpl( + loading: freezed == loading ? _value.loading! : loading, + error: freezed == error ? _value.error : error, + )); + } +} + +/// @nodoc + +class _$AddNewPlaceStateImpl implements _AddNewPlaceState { + const _$AddNewPlaceStateImpl({this.loading = false, this.error}); + + @override + @JsonKey() + final dynamic loading; + @override + final Object? error; + + @override + String toString() { + return 'AddNewPlaceState(loading: $loading, error: $error)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AddNewPlaceStateImpl && + const DeepCollectionEquality().equals(other.loading, loading) && + const DeepCollectionEquality().equals(other.error, error)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(loading), + const DeepCollectionEquality().hash(error)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$AddNewPlaceStateImplCopyWith<_$AddNewPlaceStateImpl> get copyWith => + __$$AddNewPlaceStateImplCopyWithImpl<_$AddNewPlaceStateImpl>( + this, _$identity); +} + +abstract class _AddNewPlaceState implements AddNewPlaceState { + const factory _AddNewPlaceState( + {final dynamic loading, final Object? error}) = _$AddNewPlaceStateImpl; + + @override + dynamic get loading; + @override + Object? get error; + @override + @JsonKey(ignore: true) + _$$AddNewPlaceStateImplCopyWith<_$AddNewPlaceStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart new file mode 100644 index 00000000..1cd61124 --- /dev/null +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart @@ -0,0 +1,230 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'choose_place_name_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$ChoosePlaceViewState { + dynamic get addingPlace => throw _privateConstructorUsedError; + List? get suggestions => throw _privateConstructorUsedError; + String? get placeName => throw _privateConstructorUsedError; + Object? get error => throw _privateConstructorUsedError; + DateTime? get popToPlaceList => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $ChoosePlaceViewStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChoosePlaceViewStateCopyWith<$Res> { + factory $ChoosePlaceViewStateCopyWith(ChoosePlaceViewState value, + $Res Function(ChoosePlaceViewState) then) = + _$ChoosePlaceViewStateCopyWithImpl<$Res, ChoosePlaceViewState>; + @useResult + $Res call( + {dynamic addingPlace, + List? suggestions, + String? placeName, + Object? error, + DateTime? popToPlaceList}); +} + +/// @nodoc +class _$ChoosePlaceViewStateCopyWithImpl<$Res, + $Val extends ChoosePlaceViewState> + implements $ChoosePlaceViewStateCopyWith<$Res> { + _$ChoosePlaceViewStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? addingPlace = freezed, + Object? suggestions = freezed, + Object? placeName = freezed, + Object? error = freezed, + Object? popToPlaceList = freezed, + }) { + return _then(_value.copyWith( + addingPlace: freezed == addingPlace + ? _value.addingPlace + : addingPlace // ignore: cast_nullable_to_non_nullable + as dynamic, + suggestions: freezed == suggestions + ? _value.suggestions + : suggestions // ignore: cast_nullable_to_non_nullable + as List?, + placeName: freezed == placeName + ? _value.placeName + : placeName // ignore: cast_nullable_to_non_nullable + as String?, + error: freezed == error ? _value.error : error, + popToPlaceList: freezed == popToPlaceList + ? _value.popToPlaceList + : popToPlaceList // ignore: cast_nullable_to_non_nullable + as DateTime?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ChoosePlaceViewStateImplCopyWith<$Res> + implements $ChoosePlaceViewStateCopyWith<$Res> { + factory _$$ChoosePlaceViewStateImplCopyWith(_$ChoosePlaceViewStateImpl value, + $Res Function(_$ChoosePlaceViewStateImpl) then) = + __$$ChoosePlaceViewStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {dynamic addingPlace, + List? suggestions, + String? placeName, + Object? error, + DateTime? popToPlaceList}); +} + +/// @nodoc +class __$$ChoosePlaceViewStateImplCopyWithImpl<$Res> + extends _$ChoosePlaceViewStateCopyWithImpl<$Res, _$ChoosePlaceViewStateImpl> + implements _$$ChoosePlaceViewStateImplCopyWith<$Res> { + __$$ChoosePlaceViewStateImplCopyWithImpl(_$ChoosePlaceViewStateImpl _value, + $Res Function(_$ChoosePlaceViewStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? addingPlace = freezed, + Object? suggestions = freezed, + Object? placeName = freezed, + Object? error = freezed, + Object? popToPlaceList = freezed, + }) { + return _then(_$ChoosePlaceViewStateImpl( + addingPlace: freezed == addingPlace ? _value.addingPlace! : addingPlace, + suggestions: freezed == suggestions + ? _value._suggestions + : suggestions // ignore: cast_nullable_to_non_nullable + as List?, + placeName: freezed == placeName + ? _value.placeName + : placeName // ignore: cast_nullable_to_non_nullable + as String?, + error: freezed == error ? _value.error : error, + popToPlaceList: freezed == popToPlaceList + ? _value.popToPlaceList + : popToPlaceList // ignore: cast_nullable_to_non_nullable + as DateTime?, + )); + } +} + +/// @nodoc + +class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { + const _$ChoosePlaceViewStateImpl( + {this.addingPlace = false, + final List? suggestions, + this.placeName, + this.error, + this.popToPlaceList}) + : _suggestions = suggestions; + + @override + @JsonKey() + final dynamic addingPlace; + final List? _suggestions; + @override + List? get suggestions { + final value = _suggestions; + if (value == null) return null; + if (_suggestions is EqualUnmodifiableListView) return _suggestions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + final String? placeName; + @override + final Object? error; + @override + final DateTime? popToPlaceList; + + @override + String toString() { + return 'ChoosePlaceViewState(addingPlace: $addingPlace, suggestions: $suggestions, placeName: $placeName, error: $error, popToPlaceList: $popToPlaceList)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChoosePlaceViewStateImpl && + const DeepCollectionEquality() + .equals(other.addingPlace, addingPlace) && + const DeepCollectionEquality() + .equals(other._suggestions, _suggestions) && + (identical(other.placeName, placeName) || + other.placeName == placeName) && + const DeepCollectionEquality().equals(other.error, error) && + (identical(other.popToPlaceList, popToPlaceList) || + other.popToPlaceList == popToPlaceList)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(addingPlace), + const DeepCollectionEquality().hash(_suggestions), + placeName, + const DeepCollectionEquality().hash(error), + popToPlaceList); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChoosePlaceViewStateImplCopyWith<_$ChoosePlaceViewStateImpl> + get copyWith => + __$$ChoosePlaceViewStateImplCopyWithImpl<_$ChoosePlaceViewStateImpl>( + this, _$identity); +} + +abstract class _ChoosePlaceViewState implements ChoosePlaceViewState { + const factory _ChoosePlaceViewState( + {final dynamic addingPlace, + final List? suggestions, + final String? placeName, + final Object? error, + final DateTime? popToPlaceList}) = _$ChoosePlaceViewStateImpl; + + @override + dynamic get addingPlace; + @override + List? get suggestions; + @override + String? get placeName; + @override + Object? get error; + @override + DateTime? get popToPlaceList; + @override + @JsonKey(ignore: true) + _$$ChoosePlaceViewStateImplCopyWith<_$ChoosePlaceViewStateImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart b/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart new file mode 100644 index 00000000..b7518e6c --- /dev/null +++ b/app/lib/ui/flow/geofence/places/places_list_view_model.freezed.dart @@ -0,0 +1,491 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'places_list_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$PlacesListState { + bool get loading => throw _privateConstructorUsedError; + bool get deletingPlaces => throw _privateConstructorUsedError; + String? get spaceId => throw _privateConstructorUsedError; + DateTime? get showDeletePlaceDialog => throw _privateConstructorUsedError; + ApiPlace? get placesToDelete => throw _privateConstructorUsedError; + ApiUser? get currentUser => throw _privateConstructorUsedError; + List get places => throw _privateConstructorUsedError; + List get suggestions => throw _privateConstructorUsedError; + Object? get error => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $PlacesListStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PlacesListStateCopyWith<$Res> { + factory $PlacesListStateCopyWith( + PlacesListState value, $Res Function(PlacesListState) then) = + _$PlacesListStateCopyWithImpl<$Res, PlacesListState>; + @useResult + $Res call( + {bool loading, + bool deletingPlaces, + String? spaceId, + DateTime? showDeletePlaceDialog, + ApiPlace? placesToDelete, + ApiUser? currentUser, + List places, + List suggestions, + Object? error}); + + $ApiPlaceCopyWith<$Res>? get placesToDelete; + $ApiUserCopyWith<$Res>? get currentUser; +} + +/// @nodoc +class _$PlacesListStateCopyWithImpl<$Res, $Val extends PlacesListState> + implements $PlacesListStateCopyWith<$Res> { + _$PlacesListStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = null, + Object? deletingPlaces = null, + Object? spaceId = freezed, + Object? showDeletePlaceDialog = freezed, + Object? placesToDelete = freezed, + Object? currentUser = freezed, + Object? places = null, + Object? suggestions = null, + Object? error = freezed, + }) { + return _then(_value.copyWith( + loading: null == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as bool, + deletingPlaces: null == deletingPlaces + ? _value.deletingPlaces + : deletingPlaces // ignore: cast_nullable_to_non_nullable + as bool, + spaceId: freezed == spaceId + ? _value.spaceId + : spaceId // ignore: cast_nullable_to_non_nullable + as String?, + showDeletePlaceDialog: freezed == showDeletePlaceDialog + ? _value.showDeletePlaceDialog + : showDeletePlaceDialog // ignore: cast_nullable_to_non_nullable + as DateTime?, + placesToDelete: freezed == placesToDelete + ? _value.placesToDelete + : placesToDelete // ignore: cast_nullable_to_non_nullable + as ApiPlace?, + currentUser: freezed == currentUser + ? _value.currentUser + : currentUser // ignore: cast_nullable_to_non_nullable + as ApiUser?, + places: null == places + ? _value.places + : places // ignore: cast_nullable_to_non_nullable + as List, + suggestions: null == suggestions + ? _value.suggestions + : suggestions // ignore: cast_nullable_to_non_nullable + as List, + error: freezed == error ? _value.error : error, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ApiPlaceCopyWith<$Res>? get placesToDelete { + if (_value.placesToDelete == null) { + return null; + } + + return $ApiPlaceCopyWith<$Res>(_value.placesToDelete!, (value) { + return _then(_value.copyWith(placesToDelete: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $ApiUserCopyWith<$Res>? get currentUser { + if (_value.currentUser == null) { + return null; + } + + return $ApiUserCopyWith<$Res>(_value.currentUser!, (value) { + return _then(_value.copyWith(currentUser: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$PlacesListStateImplCopyWith<$Res> + implements $PlacesListStateCopyWith<$Res> { + factory _$$PlacesListStateImplCopyWith(_$PlacesListStateImpl value, + $Res Function(_$PlacesListStateImpl) then) = + __$$PlacesListStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {bool loading, + bool deletingPlaces, + String? spaceId, + DateTime? showDeletePlaceDialog, + ApiPlace? placesToDelete, + ApiUser? currentUser, + List places, + List suggestions, + Object? error}); + + @override + $ApiPlaceCopyWith<$Res>? get placesToDelete; + @override + $ApiUserCopyWith<$Res>? get currentUser; +} + +/// @nodoc +class __$$PlacesListStateImplCopyWithImpl<$Res> + extends _$PlacesListStateCopyWithImpl<$Res, _$PlacesListStateImpl> + implements _$$PlacesListStateImplCopyWith<$Res> { + __$$PlacesListStateImplCopyWithImpl( + _$PlacesListStateImpl _value, $Res Function(_$PlacesListStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = null, + Object? deletingPlaces = null, + Object? spaceId = freezed, + Object? showDeletePlaceDialog = freezed, + Object? placesToDelete = freezed, + Object? currentUser = freezed, + Object? places = null, + Object? suggestions = null, + Object? error = freezed, + }) { + return _then(_$PlacesListStateImpl( + loading: null == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as bool, + deletingPlaces: null == deletingPlaces + ? _value.deletingPlaces + : deletingPlaces // ignore: cast_nullable_to_non_nullable + as bool, + spaceId: freezed == spaceId + ? _value.spaceId + : spaceId // ignore: cast_nullable_to_non_nullable + as String?, + showDeletePlaceDialog: freezed == showDeletePlaceDialog + ? _value.showDeletePlaceDialog + : showDeletePlaceDialog // ignore: cast_nullable_to_non_nullable + as DateTime?, + placesToDelete: freezed == placesToDelete + ? _value.placesToDelete + : placesToDelete // ignore: cast_nullable_to_non_nullable + as ApiPlace?, + currentUser: freezed == currentUser + ? _value.currentUser + : currentUser // ignore: cast_nullable_to_non_nullable + as ApiUser?, + places: null == places + ? _value._places + : places // ignore: cast_nullable_to_non_nullable + as List, + suggestions: null == suggestions + ? _value._suggestions + : suggestions // ignore: cast_nullable_to_non_nullable + as List, + error: freezed == error ? _value.error : error, + )); + } +} + +/// @nodoc + +class _$PlacesListStateImpl implements _PlacesListState { + const _$PlacesListStateImpl( + {this.loading = false, + this.deletingPlaces = false, + this.spaceId, + this.showDeletePlaceDialog, + this.placesToDelete, + this.currentUser, + final List places = const [], + final List suggestions = const [], + this.error}) + : _places = places, + _suggestions = suggestions; + + @override + @JsonKey() + final bool loading; + @override + @JsonKey() + final bool deletingPlaces; + @override + final String? spaceId; + @override + final DateTime? showDeletePlaceDialog; + @override + final ApiPlace? placesToDelete; + @override + final ApiUser? currentUser; + final List _places; + @override + @JsonKey() + List get places { + if (_places is EqualUnmodifiableListView) return _places; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_places); + } + + final List _suggestions; + @override + @JsonKey() + List get suggestions { + if (_suggestions is EqualUnmodifiableListView) return _suggestions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_suggestions); + } + + @override + final Object? error; + + @override + String toString() { + return 'PlacesListState(loading: $loading, deletingPlaces: $deletingPlaces, spaceId: $spaceId, showDeletePlaceDialog: $showDeletePlaceDialog, placesToDelete: $placesToDelete, currentUser: $currentUser, places: $places, suggestions: $suggestions, error: $error)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PlacesListStateImpl && + (identical(other.loading, loading) || other.loading == loading) && + (identical(other.deletingPlaces, deletingPlaces) || + other.deletingPlaces == deletingPlaces) && + (identical(other.spaceId, spaceId) || other.spaceId == spaceId) && + (identical(other.showDeletePlaceDialog, showDeletePlaceDialog) || + other.showDeletePlaceDialog == showDeletePlaceDialog) && + (identical(other.placesToDelete, placesToDelete) || + other.placesToDelete == placesToDelete) && + (identical(other.currentUser, currentUser) || + other.currentUser == currentUser) && + const DeepCollectionEquality().equals(other._places, _places) && + const DeepCollectionEquality() + .equals(other._suggestions, _suggestions) && + const DeepCollectionEquality().equals(other.error, error)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + loading, + deletingPlaces, + spaceId, + showDeletePlaceDialog, + placesToDelete, + currentUser, + const DeepCollectionEquality().hash(_places), + const DeepCollectionEquality().hash(_suggestions), + const DeepCollectionEquality().hash(error)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PlacesListStateImplCopyWith<_$PlacesListStateImpl> get copyWith => + __$$PlacesListStateImplCopyWithImpl<_$PlacesListStateImpl>( + this, _$identity); +} + +abstract class _PlacesListState implements PlacesListState { + const factory _PlacesListState( + {final bool loading, + final bool deletingPlaces, + final String? spaceId, + final DateTime? showDeletePlaceDialog, + final ApiPlace? placesToDelete, + final ApiUser? currentUser, + final List places, + final List suggestions, + final Object? error}) = _$PlacesListStateImpl; + + @override + bool get loading; + @override + bool get deletingPlaces; + @override + String? get spaceId; + @override + DateTime? get showDeletePlaceDialog; + @override + ApiPlace? get placesToDelete; + @override + ApiUser? get currentUser; + @override + List get places; + @override + List get suggestions; + @override + Object? get error; + @override + @JsonKey(ignore: true) + _$$PlacesListStateImplCopyWith<_$PlacesListStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$Suggestions { + String get name => throw _privateConstructorUsedError; + String get icon => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $SuggestionsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SuggestionsCopyWith<$Res> { + factory $SuggestionsCopyWith( + Suggestions value, $Res Function(Suggestions) then) = + _$SuggestionsCopyWithImpl<$Res, Suggestions>; + @useResult + $Res call({String name, String icon}); +} + +/// @nodoc +class _$SuggestionsCopyWithImpl<$Res, $Val extends Suggestions> + implements $SuggestionsCopyWith<$Res> { + _$SuggestionsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? icon = null, + }) { + return _then(_value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + icon: null == icon + ? _value.icon + : icon // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SuggestionsImplCopyWith<$Res> + implements $SuggestionsCopyWith<$Res> { + factory _$$SuggestionsImplCopyWith( + _$SuggestionsImpl value, $Res Function(_$SuggestionsImpl) then) = + __$$SuggestionsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String name, String icon}); +} + +/// @nodoc +class __$$SuggestionsImplCopyWithImpl<$Res> + extends _$SuggestionsCopyWithImpl<$Res, _$SuggestionsImpl> + implements _$$SuggestionsImplCopyWith<$Res> { + __$$SuggestionsImplCopyWithImpl( + _$SuggestionsImpl _value, $Res Function(_$SuggestionsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? icon = null, + }) { + return _then(_$SuggestionsImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + icon: null == icon + ? _value.icon + : icon // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$SuggestionsImpl implements _Suggestions { + const _$SuggestionsImpl({required this.name, required this.icon}); + + @override + final String name; + @override + final String icon; + + @override + String toString() { + return 'Suggestions(name: $name, icon: $icon)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SuggestionsImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.icon, icon) || other.icon == icon)); + } + + @override + int get hashCode => Object.hash(runtimeType, name, icon); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SuggestionsImplCopyWith<_$SuggestionsImpl> get copyWith => + __$$SuggestionsImplCopyWithImpl<_$SuggestionsImpl>(this, _$identity); +} + +abstract class _Suggestions implements Suggestions { + const factory _Suggestions( + {required final String name, + required final String icon}) = _$SuggestionsImpl; + + @override + String get name; + @override + String get icon; + @override + @JsonKey(ignore: true) + _$$SuggestionsImplCopyWith<_$SuggestionsImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/app/lib/ui/flow/home/map/map_view_model.freezed.dart b/app/lib/ui/flow/home/map/map_view_model.freezed.dart new file mode 100644 index 00000000..ce3f33ca --- /dev/null +++ b/app/lib/ui/flow/home/map/map_view_model.freezed.dart @@ -0,0 +1,572 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'map_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$MapViewState { + dynamic get loading => throw _privateConstructorUsedError; + bool get fetchingInviteCode => throw _privateConstructorUsedError; + List get userInfo => throw _privateConstructorUsedError; + List get places => throw _privateConstructorUsedError; + List get markers => throw _privateConstructorUsedError; + ApiUserInfo? get selectedUser => throw _privateConstructorUsedError; + CameraPosition? get defaultPosition => throw _privateConstructorUsedError; + String get spaceInvitationCode => throw _privateConstructorUsedError; + Object? get error => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $MapViewStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MapViewStateCopyWith<$Res> { + factory $MapViewStateCopyWith( + MapViewState value, $Res Function(MapViewState) then) = + _$MapViewStateCopyWithImpl<$Res, MapViewState>; + @useResult + $Res call( + {dynamic loading, + bool fetchingInviteCode, + List userInfo, + List places, + List markers, + ApiUserInfo? selectedUser, + CameraPosition? defaultPosition, + String spaceInvitationCode, + Object? error}); + + $ApiUserInfoCopyWith<$Res>? get selectedUser; +} + +/// @nodoc +class _$MapViewStateCopyWithImpl<$Res, $Val extends MapViewState> + implements $MapViewStateCopyWith<$Res> { + _$MapViewStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = freezed, + Object? fetchingInviteCode = null, + Object? userInfo = null, + Object? places = null, + Object? markers = null, + Object? selectedUser = freezed, + Object? defaultPosition = freezed, + Object? spaceInvitationCode = null, + Object? error = freezed, + }) { + return _then(_value.copyWith( + loading: freezed == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as dynamic, + fetchingInviteCode: null == fetchingInviteCode + ? _value.fetchingInviteCode + : fetchingInviteCode // ignore: cast_nullable_to_non_nullable + as bool, + userInfo: null == userInfo + ? _value.userInfo + : userInfo // ignore: cast_nullable_to_non_nullable + as List, + places: null == places + ? _value.places + : places // ignore: cast_nullable_to_non_nullable + as List, + markers: null == markers + ? _value.markers + : markers // ignore: cast_nullable_to_non_nullable + as List, + selectedUser: freezed == selectedUser + ? _value.selectedUser + : selectedUser // ignore: cast_nullable_to_non_nullable + as ApiUserInfo?, + defaultPosition: freezed == defaultPosition + ? _value.defaultPosition + : defaultPosition // ignore: cast_nullable_to_non_nullable + as CameraPosition?, + spaceInvitationCode: null == spaceInvitationCode + ? _value.spaceInvitationCode + : spaceInvitationCode // ignore: cast_nullable_to_non_nullable + as String, + error: freezed == error ? _value.error : error, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ApiUserInfoCopyWith<$Res>? get selectedUser { + if (_value.selectedUser == null) { + return null; + } + + return $ApiUserInfoCopyWith<$Res>(_value.selectedUser!, (value) { + return _then(_value.copyWith(selectedUser: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$MapViewStateImplCopyWith<$Res> + implements $MapViewStateCopyWith<$Res> { + factory _$$MapViewStateImplCopyWith( + _$MapViewStateImpl value, $Res Function(_$MapViewStateImpl) then) = + __$$MapViewStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {dynamic loading, + bool fetchingInviteCode, + List userInfo, + List places, + List markers, + ApiUserInfo? selectedUser, + CameraPosition? defaultPosition, + String spaceInvitationCode, + Object? error}); + + @override + $ApiUserInfoCopyWith<$Res>? get selectedUser; +} + +/// @nodoc +class __$$MapViewStateImplCopyWithImpl<$Res> + extends _$MapViewStateCopyWithImpl<$Res, _$MapViewStateImpl> + implements _$$MapViewStateImplCopyWith<$Res> { + __$$MapViewStateImplCopyWithImpl( + _$MapViewStateImpl _value, $Res Function(_$MapViewStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = freezed, + Object? fetchingInviteCode = null, + Object? userInfo = null, + Object? places = null, + Object? markers = null, + Object? selectedUser = freezed, + Object? defaultPosition = freezed, + Object? spaceInvitationCode = null, + Object? error = freezed, + }) { + return _then(_$MapViewStateImpl( + loading: freezed == loading ? _value.loading! : loading, + fetchingInviteCode: null == fetchingInviteCode + ? _value.fetchingInviteCode + : fetchingInviteCode // ignore: cast_nullable_to_non_nullable + as bool, + userInfo: null == userInfo + ? _value._userInfo + : userInfo // ignore: cast_nullable_to_non_nullable + as List, + places: null == places + ? _value._places + : places // ignore: cast_nullable_to_non_nullable + as List, + markers: null == markers + ? _value._markers + : markers // ignore: cast_nullable_to_non_nullable + as List, + selectedUser: freezed == selectedUser + ? _value.selectedUser + : selectedUser // ignore: cast_nullable_to_non_nullable + as ApiUserInfo?, + defaultPosition: freezed == defaultPosition + ? _value.defaultPosition + : defaultPosition // ignore: cast_nullable_to_non_nullable + as CameraPosition?, + spaceInvitationCode: null == spaceInvitationCode + ? _value.spaceInvitationCode + : spaceInvitationCode // ignore: cast_nullable_to_non_nullable + as String, + error: freezed == error ? _value.error : error, + )); + } +} + +/// @nodoc + +class _$MapViewStateImpl implements _MapViewState { + const _$MapViewStateImpl( + {this.loading = false, + this.fetchingInviteCode = false, + final List userInfo = const [], + final List places = const [], + final List markers = const [], + this.selectedUser, + this.defaultPosition, + this.spaceInvitationCode = '', + this.error}) + : _userInfo = userInfo, + _places = places, + _markers = markers; + + @override + @JsonKey() + final dynamic loading; + @override + @JsonKey() + final bool fetchingInviteCode; + final List _userInfo; + @override + @JsonKey() + List get userInfo { + if (_userInfo is EqualUnmodifiableListView) return _userInfo; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_userInfo); + } + + final List _places; + @override + @JsonKey() + List get places { + if (_places is EqualUnmodifiableListView) return _places; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_places); + } + + final List _markers; + @override + @JsonKey() + List get markers { + if (_markers is EqualUnmodifiableListView) return _markers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_markers); + } + + @override + final ApiUserInfo? selectedUser; + @override + final CameraPosition? defaultPosition; + @override + @JsonKey() + final String spaceInvitationCode; + @override + final Object? error; + + @override + String toString() { + return 'MapViewState(loading: $loading, fetchingInviteCode: $fetchingInviteCode, userInfo: $userInfo, places: $places, markers: $markers, selectedUser: $selectedUser, defaultPosition: $defaultPosition, spaceInvitationCode: $spaceInvitationCode, error: $error)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MapViewStateImpl && + const DeepCollectionEquality().equals(other.loading, loading) && + (identical(other.fetchingInviteCode, fetchingInviteCode) || + other.fetchingInviteCode == fetchingInviteCode) && + const DeepCollectionEquality().equals(other._userInfo, _userInfo) && + const DeepCollectionEquality().equals(other._places, _places) && + const DeepCollectionEquality().equals(other._markers, _markers) && + (identical(other.selectedUser, selectedUser) || + other.selectedUser == selectedUser) && + (identical(other.defaultPosition, defaultPosition) || + other.defaultPosition == defaultPosition) && + (identical(other.spaceInvitationCode, spaceInvitationCode) || + other.spaceInvitationCode == spaceInvitationCode) && + const DeepCollectionEquality().equals(other.error, error)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(loading), + fetchingInviteCode, + const DeepCollectionEquality().hash(_userInfo), + const DeepCollectionEquality().hash(_places), + const DeepCollectionEquality().hash(_markers), + selectedUser, + defaultPosition, + spaceInvitationCode, + const DeepCollectionEquality().hash(error)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MapViewStateImplCopyWith<_$MapViewStateImpl> get copyWith => + __$$MapViewStateImplCopyWithImpl<_$MapViewStateImpl>(this, _$identity); +} + +abstract class _MapViewState implements MapViewState { + const factory _MapViewState( + {final dynamic loading, + final bool fetchingInviteCode, + final List userInfo, + final List places, + final List markers, + final ApiUserInfo? selectedUser, + final CameraPosition? defaultPosition, + final String spaceInvitationCode, + final Object? error}) = _$MapViewStateImpl; + + @override + dynamic get loading; + @override + bool get fetchingInviteCode; + @override + List get userInfo; + @override + List get places; + @override + List get markers; + @override + ApiUserInfo? get selectedUser; + @override + CameraPosition? get defaultPosition; + @override + String get spaceInvitationCode; + @override + Object? get error; + @override + @JsonKey(ignore: true) + _$$MapViewStateImplCopyWith<_$MapViewStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$UserMarker { + String get userId => throw _privateConstructorUsedError; + String get userName => throw _privateConstructorUsedError; + ui.Image? get imageUrl => throw _privateConstructorUsedError; + double get latitude => throw _privateConstructorUsedError; + double get longitude => throw _privateConstructorUsedError; + bool get isSelected => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $UserMarkerCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $UserMarkerCopyWith<$Res> { + factory $UserMarkerCopyWith( + UserMarker value, $Res Function(UserMarker) then) = + _$UserMarkerCopyWithImpl<$Res, UserMarker>; + @useResult + $Res call( + {String userId, + String userName, + ui.Image? imageUrl, + double latitude, + double longitude, + bool isSelected}); +} + +/// @nodoc +class _$UserMarkerCopyWithImpl<$Res, $Val extends UserMarker> + implements $UserMarkerCopyWith<$Res> { + _$UserMarkerCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? userId = null, + Object? userName = null, + Object? imageUrl = freezed, + Object? latitude = null, + Object? longitude = null, + Object? isSelected = null, + }) { + return _then(_value.copyWith( + userId: null == userId + ? _value.userId + : userId // ignore: cast_nullable_to_non_nullable + as String, + userName: null == userName + ? _value.userName + : userName // ignore: cast_nullable_to_non_nullable + as String, + imageUrl: freezed == imageUrl + ? _value.imageUrl + : imageUrl // ignore: cast_nullable_to_non_nullable + as ui.Image?, + latitude: null == latitude + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as double, + longitude: null == longitude + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as double, + isSelected: null == isSelected + ? _value.isSelected + : isSelected // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$UserMarkerImplCopyWith<$Res> + implements $UserMarkerCopyWith<$Res> { + factory _$$UserMarkerImplCopyWith( + _$UserMarkerImpl value, $Res Function(_$UserMarkerImpl) then) = + __$$UserMarkerImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String userId, + String userName, + ui.Image? imageUrl, + double latitude, + double longitude, + bool isSelected}); +} + +/// @nodoc +class __$$UserMarkerImplCopyWithImpl<$Res> + extends _$UserMarkerCopyWithImpl<$Res, _$UserMarkerImpl> + implements _$$UserMarkerImplCopyWith<$Res> { + __$$UserMarkerImplCopyWithImpl( + _$UserMarkerImpl _value, $Res Function(_$UserMarkerImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? userId = null, + Object? userName = null, + Object? imageUrl = freezed, + Object? latitude = null, + Object? longitude = null, + Object? isSelected = null, + }) { + return _then(_$UserMarkerImpl( + userId: null == userId + ? _value.userId + : userId // ignore: cast_nullable_to_non_nullable + as String, + userName: null == userName + ? _value.userName + : userName // ignore: cast_nullable_to_non_nullable + as String, + imageUrl: freezed == imageUrl + ? _value.imageUrl + : imageUrl // ignore: cast_nullable_to_non_nullable + as ui.Image?, + latitude: null == latitude + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as double, + longitude: null == longitude + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as double, + isSelected: null == isSelected + ? _value.isSelected + : isSelected // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc + +class _$UserMarkerImpl implements _UserMarker { + const _$UserMarkerImpl( + {required this.userId, + required this.userName, + required this.imageUrl, + required this.latitude, + required this.longitude, + required this.isSelected}); + + @override + final String userId; + @override + final String userName; + @override + final ui.Image? imageUrl; + @override + final double latitude; + @override + final double longitude; + @override + final bool isSelected; + + @override + String toString() { + return 'UserMarker(userId: $userId, userName: $userName, imageUrl: $imageUrl, latitude: $latitude, longitude: $longitude, isSelected: $isSelected)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$UserMarkerImpl && + (identical(other.userId, userId) || other.userId == userId) && + (identical(other.userName, userName) || + other.userName == userName) && + (identical(other.imageUrl, imageUrl) || + other.imageUrl == imageUrl) && + (identical(other.latitude, latitude) || + other.latitude == latitude) && + (identical(other.longitude, longitude) || + other.longitude == longitude) && + (identical(other.isSelected, isSelected) || + other.isSelected == isSelected)); + } + + @override + int get hashCode => Object.hash( + runtimeType, userId, userName, imageUrl, latitude, longitude, isSelected); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$UserMarkerImplCopyWith<_$UserMarkerImpl> get copyWith => + __$$UserMarkerImplCopyWithImpl<_$UserMarkerImpl>(this, _$identity); +} + +abstract class _UserMarker implements UserMarker { + const factory _UserMarker( + {required final String userId, + required final String userName, + required final ui.Image? imageUrl, + required final double latitude, + required final double longitude, + required final bool isSelected}) = _$UserMarkerImpl; + + @override + String get userId; + @override + String get userName; + @override + ui.Image? get imageUrl; + @override + double get latitude; + @override + double get longitude; + @override + bool get isSelected; + @override + @JsonKey(ignore: true) + _$$UserMarkerImplCopyWith<_$UserMarkerImpl> get copyWith => + throw _privateConstructorUsedError; +} From c080c96e0df40068918034b6cb26f95dc61850db Mon Sep 17 00:00:00 2001 From: kaushik Date: Tue, 25 Jun 2024 15:06:02 +0530 Subject: [PATCH 24/65] Fix conflict --- app/lib/ui/flow/home/map/map_view.dart | 224 +++++++++++++++---------- 1 file changed, 140 insertions(+), 84 deletions(-) diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index a82887eb..128f9c90 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -35,7 +35,7 @@ class _MapScreenState extends ConsumerState { late MapViewNotifier notifier; final Completer _controller = Completer(); final _cameraPosition = - const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); + const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); final List _markers = []; final List _places = []; @@ -79,36 +79,92 @@ class _MapScreenState extends ConsumerState { markers: _markers.toSet(), ), ), - Positioned( - bottom: 0, - left: 0, - right: 0, - child: SpaceUserFooter( - members: state.userInfo, - selectedUser: state.selectedUser, - isEnabled: !state.loading, - onAddMemberTap: () { - notifier.onAddMemberTap(widget.space!.space.id); - }, - onMemberTap: (member) { - notifier.showMemberDetail(member); - }, - onRelocateTap: () {}, - onPlacesTap: () { - if (widget.space == null) return; - AppRoute.placesList(widget.space!.space.id).push(context); - }, - onDismiss: () => notifier.onDismissMemberDetail(), - onTapTimeline: () {}, - ), + Positioned(bottom: 0, left: 0, right: 0, child: _bottomFooters(state)), + ], + ); + } + + Widget _bottomFooters(MapViewState state) { + final enabled = !state.hasLocationEnabled || + !state.hasLocationServiceEnabled || + !state.hasNotificationEnabled; + + return Column( + children: [ + SpaceUserFooter( + members: state.userInfo, + selectedUser: state.selectedUser, + isEnabled: !state.loading, + onAddMemberTap: () { + notifier.onAddMemberTap(widget.space!.space.id); + }, + onMemberTap: (member) { + notifier.showMemberDetail(member); + }, + onRelocateTap: () {}, + onPlacesTap: () {}, + onDismiss: () => notifier.onDismissMemberDetail(), + onTapTimeline: () {}, ), + Visibility(visible: enabled, child: _permissionFooter(state)) ], ); } + Widget _permissionFooter(MapViewState state) { + final locationEnabled = + state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; + final (title, subTitle) = _permissionFooterContent(state); + + return OnTapScale( + onTap: () { + (!locationEnabled) + ? notifier.showEnableLocationDialog() + : AppRoute.enablePermission.push(context); + }, + child: Container( + padding: const EdgeInsets.all(16), + width: double.infinity, + color: !locationEnabled + ? context.colorScheme.alert + : context.colorScheme.secondary, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: AppTextStyle.body2.copyWith( + color: context.colorScheme.textInversePrimary, + ), + ), + const SizedBox(height: 4), + Text( + subTitle, + style: AppTextStyle.caption.copyWith( + color: context.colorScheme.textInverseDisabled, + ), + ) + ], + ), + ), + Icon( + Icons.arrow_forward_ios_rounded, + size: 16, + color: context.colorScheme.textInversePrimary, + ) + ], + ), + ), + ); + } + (String, String) _permissionFooterContent(MapViewState state) { final locationEnabled = - state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; + state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; String title = ''; String subTitle = ''; @@ -141,7 +197,7 @@ class _MapScreenState extends ConsumerState { final controller = await _controller.future; if (isDarkMode) { final style = - await rootBundle.loadString('assets/map/map_theme_night.json'); + await rootBundle.loadString('assets/map/map_theme_night.json'); controller.setMapStyle(style); } else { controller.setMapStyle(null); @@ -150,57 +206,57 @@ class _MapScreenState extends ConsumerState { void _observeMapCameraPosition() { ref.listen(mapViewStateProvider.select((state) => state.defaultPosition), - (previous, next) async { - if (next != null) { - final GoogleMapController controller = await _controller.future; - await controller.animateCamera(CameraUpdate.newCameraPosition(next)); - } - }); + (previous, next) async { + if (next != null) { + final GoogleMapController controller = await _controller.future; + await controller.animateCamera(CameraUpdate.newCameraPosition(next)); + } + }); } void _observeNavigation() { ref.listen( mapViewStateProvider.select((state) => state.spaceInvitationCode), - (_, next) { - if (next.isNotEmpty) { - AppRoute.inviteCode( + (_, next) { + if (next.isNotEmpty) { + AppRoute.inviteCode( code: next, spaceName: widget.space?.space.name ?? '') - .push(context); - } - }); + .push(context); + } + }); } void _observeMarkerChange() { ref.listen(mapViewStateProvider.select((state) => state.markers), - (_, next) { - if (next.isNotEmpty) { - for (final item in next) { - _buildMarker(item); - } - } - }); + (_, next) { + if (next.isNotEmpty) { + for (final item in next) { + _buildMarker(item); + } + } + }); } void _observeShowEnableLocationPrompt(BuildContext context) { ref.listen(mapViewStateProvider.select((state) => state.showLocationDialog), - (_, next) { - if (next != null) { - showDialog( - context: context, - builder: (context) { - return PermissionDialog( - title: context.l10n.enable_location_service_title, - subTitle1: context.l10n.enable_location_service_message, - onDismiss: () {}, - goToSettings: () { - openAppSettings(); - Navigator.of(context).pop(); + (_, next) { + if (next != null) { + showDialog( + context: context, + builder: (context) { + return PermissionDialog( + title: context.l10n.enable_location_service_title, + subTitle1: context.l10n.enable_location_service_message, + onDismiss: () {}, + goToSettings: () { + openAppSettings(); + Navigator.of(context).pop(); + }, + ); }, ); - }, - ); - } - }); + } + }); } void _observeMemberPlace(BuildContext context) { @@ -256,13 +312,13 @@ class _MapScreenState extends ConsumerState { } Future _mapMarker( - bool isSelected, - String userName, - ui.Image? imageUrl, - Color markerBgColor, - Color iconBgColor, - TextStyle textStyle, - ) async { + bool isSelected, + String userName, + ui.Image? imageUrl, + Color markerBgColor, + Color iconBgColor, + TextStyle textStyle, + ) async { if (imageUrl != null) { return await _userImageMarker(userName, imageUrl, isSelected, markerBgColor, iconBgColor, textStyle); @@ -273,12 +329,12 @@ class _MapScreenState extends ConsumerState { } Future _userCharMarker( - bool isSelected, - String userName, - Color markerBgColor, - Color iconBgColor, - TextStyle textStyle, - ) async { + bool isSelected, + String userName, + Color markerBgColor, + Color iconBgColor, + TextStyle textStyle, + ) async { final pictureRecorder = ui.PictureRecorder(); final canvas = Canvas(pictureRecorder); @@ -300,7 +356,7 @@ class _MapScreenState extends ConsumerState { final img = await picture.toImage(markerSize.toInt(), markerSize.toInt()); final byteData = await img.toByteData(format: ui.ImageByteFormat.png); final bitmapDescriptor = - BitmapDescriptor.fromBytes(byteData!.buffer.asUint8List()); + BitmapDescriptor.fromBytes(byteData!.buffer.asUint8List()); return bitmapDescriptor; } @@ -326,13 +382,13 @@ class _MapScreenState extends ConsumerState { } Future _userImageMarker( - String userName, - ui.Image uiImage, - bool isSelected, - Color markerBgColor, - Color iconBgColor, - TextStyle textStyle, - ) async { + String userName, + ui.Image uiImage, + bool isSelected, + Color markerBgColor, + Color iconBgColor, + TextStyle textStyle, + ) async { // Prepare the canvas to draw the rounded rectangle and the image final recorder = ui.PictureRecorder(); final canvas = ui.Canvas( @@ -362,11 +418,11 @@ class _MapScreenState extends ConsumerState { // End recording and create an image from the canvas final picture = recorder.endRecording(); final imgData = - await picture.toImage(markerSize.toInt(), markerSize.toInt()); + await picture.toImage(markerSize.toInt(), markerSize.toInt()); final data = await imgData.toByteData(format: ui.ImageByteFormat.png); final bitmapDescriptor = - BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); + BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); return bitmapDescriptor; } @@ -420,4 +476,4 @@ class _MapScreenState extends ConsumerState { }); }); } -} +} \ No newline at end of file From 8ff92c9672f38b406b0d5df95171f92f0be8db76 Mon Sep 17 00:00:00 2001 From: kaushik Date: Tue, 25 Jun 2024 17:22:11 +0530 Subject: [PATCH 25/65] Fix app place api --- .../places/places_list_view_model.dart | 1 + data/lib/api/place/api_place.dart | 26 +++++++++++-------- data/lib/api/place/api_place.freezed.dart | 16 +++++++----- data/lib/api/place/api_place.g.dart | 22 ++++++++++++---- data/lib/service/place_service.dart | 9 +++---- 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/app/lib/ui/flow/geofence/places/places_list_view_model.dart b/app/lib/ui/flow/geofence/places/places_list_view_model.dart index d8cd121c..b91978d5 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view_model.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view_model.dart @@ -28,6 +28,7 @@ class PlacesListViewNotifier extends StateNotifier { try { state = state.copyWith(loading: true, spaceId: spaceId); placeService.getAllPlacesStream(spaceId).listen((places) { + if (!mounted) return; suggestionPlaces(places); state = state.copyWith(places: places, loading: false); }); diff --git a/data/lib/api/place/api_place.dart b/data/lib/api/place/api_place.dart index 1a91e4f8..c88a238e 100644 --- a/data/lib/api/place/api_place.dart +++ b/data/lib/api/place/api_place.dart @@ -4,8 +4,6 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'api_place.freezed.dart'; part 'api_place.g.dart'; -const geofenceDefaultPlaceRadius = 200.0; - @freezed class ApiPlace with _$ApiPlace { const ApiPlace._(); @@ -17,12 +15,12 @@ class ApiPlace with _$ApiPlace { required String name, required double latitude, required double longitude, - required double radius, - DateTime? created_at, + @Default(200.0) double radius, + @TimeStampJsonConverter() DateTime? created_at, }) = _ApiPlace; factory ApiPlace.fromJson(Map data) => - _$ApiPlaceFromJson(_convertTimestamps(data)); + _$ApiPlaceFromJson(data); factory ApiPlace.fromFireStore( DocumentSnapshot> snapshot, @@ -34,12 +32,6 @@ class ApiPlace with _$ApiPlace { Map toFireStore(ApiPlace space) => space.toJson(); } -Map _convertTimestamps(Map json) { - json.update('created_at', (value) => (value as Timestamp).toDate().toString(), - ifAbsent: () => null); - return json; -} - @freezed class ApiPlaceMemberSetting with _$ApiPlaceMemberSetting { const ApiPlaceMemberSetting._(); @@ -65,3 +57,15 @@ class ApiPlaceMemberSetting with _$ApiPlaceMemberSetting { Map toFireStore(ApiPlaceMemberSetting space) => space.toJson(); } + +class TimeStampJsonConverter extends JsonConverter { + const TimeStampJsonConverter(); + + @override + DateTime fromJson(Timestamp json) { + return json.toDate(); + } + + @override + Timestamp toJson(DateTime object) => Timestamp.fromDate(object); +} diff --git a/data/lib/api/place/api_place.freezed.dart b/data/lib/api/place/api_place.freezed.dart index b232bdf1..d3a28d3d 100644 --- a/data/lib/api/place/api_place.freezed.dart +++ b/data/lib/api/place/api_place.freezed.dart @@ -27,6 +27,7 @@ mixin _$ApiPlace { double get latitude => throw _privateConstructorUsedError; double get longitude => throw _privateConstructorUsedError; double get radius => throw _privateConstructorUsedError; + @TimeStampJsonConverter() DateTime? get created_at => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @@ -48,7 +49,7 @@ abstract class $ApiPlaceCopyWith<$Res> { double latitude, double longitude, double radius, - DateTime? created_at}); + @TimeStampJsonConverter() DateTime? created_at}); } /// @nodoc @@ -126,7 +127,7 @@ abstract class _$$ApiPlaceImplCopyWith<$Res> double latitude, double longitude, double radius, - DateTime? created_at}); + @TimeStampJsonConverter() DateTime? created_at}); } /// @nodoc @@ -196,8 +197,8 @@ class _$ApiPlaceImpl extends _ApiPlace { required this.name, required this.latitude, required this.longitude, - required this.radius, - this.created_at}) + this.radius = 200.0, + @TimeStampJsonConverter() this.created_at}) : super._(); factory _$ApiPlaceImpl.fromJson(Map json) => @@ -216,8 +217,10 @@ class _$ApiPlaceImpl extends _ApiPlace { @override final double longitude; @override + @JsonKey() final double radius; @override + @TimeStampJsonConverter() final DateTime? created_at; @override @@ -272,8 +275,8 @@ abstract class _ApiPlace extends ApiPlace { required final String name, required final double latitude, required final double longitude, - required final double radius, - final DateTime? created_at}) = _$ApiPlaceImpl; + final double radius, + @TimeStampJsonConverter() final DateTime? created_at}) = _$ApiPlaceImpl; const _ApiPlace._() : super._(); factory _ApiPlace.fromJson(Map json) = @@ -294,6 +297,7 @@ abstract class _ApiPlace extends ApiPlace { @override double get radius; @override + @TimeStampJsonConverter() DateTime? get created_at; @override @JsonKey(ignore: true) diff --git a/data/lib/api/place/api_place.g.dart b/data/lib/api/place/api_place.g.dart index eadfeb99..247e37c4 100644 --- a/data/lib/api/place/api_place.g.dart +++ b/data/lib/api/place/api_place.g.dart @@ -14,10 +14,9 @@ _$ApiPlaceImpl _$$ApiPlaceImplFromJson(Map json) => name: json['name'] as String, latitude: (json['latitude'] as num).toDouble(), longitude: (json['longitude'] as num).toDouble(), - radius: (json['radius'] as num).toDouble(), - created_at: json['created_at'] == null - ? null - : DateTime.parse(json['created_at'] as String), + radius: (json['radius'] as num?)?.toDouble() ?? 200.0, + created_at: _$JsonConverterFromJson( + json['created_at'], const TimeStampJsonConverter().fromJson), ); Map _$$ApiPlaceImplToJson(_$ApiPlaceImpl instance) => @@ -29,9 +28,22 @@ Map _$$ApiPlaceImplToJson(_$ApiPlaceImpl instance) => 'latitude': instance.latitude, 'longitude': instance.longitude, 'radius': instance.radius, - 'created_at': instance.created_at?.toIso8601String(), + 'created_at': _$JsonConverterToJson( + instance.created_at, const TimeStampJsonConverter().toJson), }; +Value? _$JsonConverterFromJson( + Object? json, + Value? Function(Json json) fromJson, +) => + json == null ? null : fromJson(json as Json); + +Json? _$JsonConverterToJson( + Value? value, + Json? Function(Value value) toJson, +) => + value == null ? null : toJson(value); + _$ApiPlaceMemberSettingImpl _$$ApiPlaceMemberSettingImplFromJson( Map json) => _$ApiPlaceMemberSettingImpl( diff --git a/data/lib/service/place_service.dart b/data/lib/service/place_service.dart index 4598f19d..0470b796 100644 --- a/data/lib/service/place_service.dart +++ b/data/lib/service/place_service.dart @@ -46,30 +46,29 @@ class PlaceService { String createdBy, List spaceMemberIds, ) async { + final placeDoc = spacePlacesRef(spaceId).doc(); - print('XXX place doc:${placeDoc.id}'); + final place = ApiPlace( id: placeDoc.id, space_id: spaceId, created_by: createdBy, latitude: latitude, longitude: longitude, - radius: geofenceDefaultPlaceRadius, name: name, created_at: DateTime.now(), ); - print('XXX places:${place}'); await placeDoc.set(place.toJson()); - print('XXX place after set'); + final settings = spaceMemberIds.map((memberId) { final filterIds = spaceMemberIds.where((id) => id != memberId).toList(); return ApiPlaceMemberSetting( user_id: memberId, place_id: place.id, alert_enabled: true, - arrival_alert_for: filterIds, leave_alert_for: filterIds, + arrival_alert_for: filterIds, ); }).toList(); From fc179a7a526feadfc87b93e66cf0aeda0ec4d9b2 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 26 Jun 2024 10:21:15 +0530 Subject: [PATCH 26/65] Minor fixes --- .../add/addnew/add_new_place_view.dart | 66 +++++++------- .../add/addnew/add_new_place_view_model.dart | 4 +- .../add/locate/locate_on_map_view.dart | 4 +- .../add/locate/locate_on_map_view_model.dart | 1 - .../locate_on_map_view_model.freezed.dart | 32 ++----- .../add/placename/choose_place_name_view.dart | 91 ++++++++++--------- .../choose_place_name_view_model.dart | 1 - .../choose_place_name_view_model.freezed.dart | 24 +---- .../geofence/places/places_list_view.dart | 11 +++ data/lib/api/place/api_place.dart | 14 +-- data/lib/converter/time_converter.dart | 14 +++ 11 files changed, 119 insertions(+), 143 deletions(-) create mode 100644 data/lib/converter/time_converter.dart diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart index 39341fe0..baa28290 100644 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart @@ -9,6 +9,7 @@ import 'package:yourspace_flutter/ui/app_route.dart'; import 'package:yourspace_flutter/ui/components/app_page.dart'; import '../../../../../gen/assets.gen.dart'; +import '../../../../components/error_snakebar.dart'; import 'add_new_place_view_model.dart'; class AddNewPlaceView extends ConsumerStatefulWidget { @@ -25,32 +26,29 @@ class _AddNewPlaceViewState extends ConsumerState { @override Widget build(BuildContext context) { - notifier = ref.watch(addNewPLaceStateProvider.notifier); + notifier = ref.watch(addNewPlaceStateProvider.notifier); + + _observeError(); return AppPage( title: context.l10n.add_new_place_title, - body: _body(), - ); - } - - Widget _body() { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _searchTextField(), - const SizedBox(height: 56), - _locateOnMapView(), - const SizedBox(height: 40), - Text( - context.l10n.add_new_place_suggestion_text, - style: AppTextStyle.caption.copyWith( - color: context.colorScheme.textDisabled, + body: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _searchTextField(), + const SizedBox(height: 40), + _locateOnMapView(), + const SizedBox(height: 40), + Text( + context.l10n.add_new_place_suggestion_text, + style: AppTextStyle.caption.copyWith( + color: context.colorScheme.textDisabled, + ), ), - ), - _placeSuggestionView() - ], + ], + ), ), ); } @@ -76,19 +74,12 @@ class _AddNewPlaceViewState extends ConsumerState { color: context.colorScheme.textDisabled, ), contentPadding: const EdgeInsets.symmetric(vertical: 0), - prefixIconConstraints: const BoxConstraints( - minHeight: 0, - minWidth: 0, - ), - border: UnderlineInputBorder( - borderSide: BorderSide( - color: context.colorScheme.textDisabled, - ), + prefixIconConstraints: const BoxConstraints(), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(color: context.colorScheme.outline), ), focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: context.colorScheme.primary, - ), + borderSide: BorderSide(color: context.colorScheme.primary), ), ), ), @@ -135,7 +126,12 @@ class _AddNewPlaceViewState extends ConsumerState { ); } - Widget _placeSuggestionView() { - return Container(); + void _observeError() { + ref.listen(addNewPlaceStateProvider.select((state) => state.error), + (previous, next) { + if (next != null) { + showErrorSnackBar(context, next.toString()); + } + }); } } diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart index 804928c3..609cb1da 100644 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart @@ -7,7 +7,7 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'add_new_place_view_model.freezed.dart'; -final addNewPLaceStateProvider = StateNotifierProvider.autoDispose< +final addNewPlaceStateProvider = StateNotifierProvider.autoDispose< AddNewPlaceViewNotifier, AddNewPlaceState>((ref) { return AddNewPlaceViewNotifier(ref.read(placeServiceProvider)); }); @@ -34,7 +34,7 @@ class AddNewPlaceViewNotifier extends StateNotifier { } catch (error, stack) { state = state.copyWith(error: error, loading: false); logger.e( - 'PlaceListNotifier: Error while deleting place', + 'AddNewPlaceViewNotifier: Error while finding place', error: error, stackTrace: stack, ); diff --git a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart index cf91abef..e30929ab 100644 --- a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart +++ b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart @@ -82,14 +82,14 @@ class _LocateOnMapViewState extends ConsumerState { onCameraMove: notifier.showLocateBtn, ), ), - Center(child: _centerLocateView()), + Center(child: _locateMarkerView()), Align( alignment: Alignment.bottomRight, child: _locateIconButton(context)) ]), ); } - Widget _centerLocateView() { + Widget _locateMarkerView() { return Container( width: 40, height: 40, diff --git a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.dart b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.dart index fdd20126..d9fb2a02 100644 --- a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.dart +++ b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.dart @@ -21,7 +21,6 @@ class LocateOnMapVieNotifier extends StateNotifier { @freezed class LocateOnMapState with _$LocateOnMapState { const factory LocateOnMapState({ - @Default(false) bool loading, CameraPosition? centerPosition, }) = _LocateOnMapState; } diff --git a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.freezed.dart index b884306a..15118a85 100644 --- a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.freezed.dart +++ b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view_model.freezed.dart @@ -16,7 +16,6 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$LocateOnMapState { - bool get loading => throw _privateConstructorUsedError; CameraPosition? get centerPosition => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -30,7 +29,7 @@ abstract class $LocateOnMapStateCopyWith<$Res> { LocateOnMapState value, $Res Function(LocateOnMapState) then) = _$LocateOnMapStateCopyWithImpl<$Res, LocateOnMapState>; @useResult - $Res call({bool loading, CameraPosition? centerPosition}); + $Res call({CameraPosition? centerPosition}); } /// @nodoc @@ -46,14 +45,9 @@ class _$LocateOnMapStateCopyWithImpl<$Res, $Val extends LocateOnMapState> @pragma('vm:prefer-inline') @override $Res call({ - Object? loading = null, Object? centerPosition = freezed, }) { return _then(_value.copyWith( - loading: null == loading - ? _value.loading - : loading // ignore: cast_nullable_to_non_nullable - as bool, centerPosition: freezed == centerPosition ? _value.centerPosition : centerPosition // ignore: cast_nullable_to_non_nullable @@ -70,7 +64,7 @@ abstract class _$$LocateOnMapStateImplCopyWith<$Res> __$$LocateOnMapStateImplCopyWithImpl<$Res>; @override @useResult - $Res call({bool loading, CameraPosition? centerPosition}); + $Res call({CameraPosition? centerPosition}); } /// @nodoc @@ -84,14 +78,9 @@ class __$$LocateOnMapStateImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? loading = null, Object? centerPosition = freezed, }) { return _then(_$LocateOnMapStateImpl( - loading: null == loading - ? _value.loading - : loading // ignore: cast_nullable_to_non_nullable - as bool, centerPosition: freezed == centerPosition ? _value.centerPosition : centerPosition // ignore: cast_nullable_to_non_nullable @@ -103,17 +92,14 @@ class __$$LocateOnMapStateImplCopyWithImpl<$Res> /// @nodoc class _$LocateOnMapStateImpl implements _LocateOnMapState { - const _$LocateOnMapStateImpl({this.loading = false, this.centerPosition}); + const _$LocateOnMapStateImpl({this.centerPosition}); - @override - @JsonKey() - final bool loading; @override final CameraPosition? centerPosition; @override String toString() { - return 'LocateOnMapState(loading: $loading, centerPosition: $centerPosition)'; + return 'LocateOnMapState(centerPosition: $centerPosition)'; } @override @@ -121,13 +107,12 @@ class _$LocateOnMapStateImpl implements _LocateOnMapState { return identical(this, other) || (other.runtimeType == runtimeType && other is _$LocateOnMapStateImpl && - (identical(other.loading, loading) || other.loading == loading) && (identical(other.centerPosition, centerPosition) || other.centerPosition == centerPosition)); } @override - int get hashCode => Object.hash(runtimeType, loading, centerPosition); + int get hashCode => Object.hash(runtimeType, centerPosition); @JsonKey(ignore: true) @override @@ -138,12 +123,9 @@ class _$LocateOnMapStateImpl implements _LocateOnMapState { } abstract class _LocateOnMapState implements LocateOnMapState { - const factory _LocateOnMapState( - {final bool loading, - final CameraPosition? centerPosition}) = _$LocateOnMapStateImpl; + const factory _LocateOnMapState({final CameraPosition? centerPosition}) = + _$LocateOnMapStateImpl; - @override - bool get loading; @override CameraPosition? get centerPosition; @override diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart index 591abace..def8b8aa 100644 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart @@ -13,6 +13,7 @@ import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_na import '../../../../../domain/extenstions/widget_extensions.dart'; import '../../../../../gen/assets.gen.dart'; +import '../../../../components/error_snakebar.dart'; import '../../../home/map/map_view.dart'; class ChoosePlaceNameView extends ConsumerStatefulWidget { @@ -45,36 +46,34 @@ class _ChoosePlaceNameViewState extends ConsumerState { @override Widget build(BuildContext context) { + final state = ref.watch(choosePlaceViewStateProvider); + + _observeError(); _observePopToPlacesListScreen(); + return AppPage( title: context.l10n.choose_place_screen_title, - body: _body(), - ); - } - - Widget _body() { - final state = ref.watch(choosePlaceViewStateProvider); - - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _searchTextField(), - const SizedBox(height: 40), - Text( - context.l10n.choose_place_suggestion_text, - style: AppTextStyle.caption - .copyWith(color: context.colorScheme.textDisabled), - ), - const SizedBox(height: 16), - _suggestionsView(state.suggestions), - const Spacer(), - Align( - alignment: Alignment.center, - child: _addPlaceView(state), - ) - ], + body: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _searchTextField(), + const SizedBox(height: 40), + Text( + context.l10n.choose_place_suggestion_text, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), + ), + const SizedBox(height: 16), + _suggestionsView(state.suggestions), + const Spacer(), + Align( + alignment: Alignment.center, + child: _addPlaceButtonView(state), + ) + ], + ), ), ); } @@ -84,6 +83,13 @@ class _ChoosePlaceNameViewState extends ConsumerState { children: [ TextField( controller: _textController, + onChanged: (value) { + if (value.isEmpty) { + setState(() { + _textController.text = ''; + }); + } + }, style: AppTextStyle.subtitle3, decoration: InputDecoration( prefixIcon: Padding( @@ -98,19 +104,12 @@ class _ChoosePlaceNameViewState extends ConsumerState { color: context.colorScheme.textDisabled, ), contentPadding: const EdgeInsets.symmetric(vertical: 0), - prefixIconConstraints: const BoxConstraints( - minHeight: 0, - minWidth: 0, - ), - border: UnderlineInputBorder( - borderSide: BorderSide( - color: context.colorScheme.textDisabled, - ), + prefixIconConstraints: const BoxConstraints(), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(color: context.colorScheme.outline), ), focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: context.colorScheme.primary, - ), + borderSide: BorderSide(color: context.colorScheme.primary), ), ), ), @@ -136,9 +135,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { style: AppTextStyle.body2 .copyWith(color: context.colorScheme.textSecondary), ), - labelPadding: const EdgeInsets.symmetric( - horizontal: 16, - ), + labelPadding: const EdgeInsets.symmetric(horizontal: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), ), @@ -150,8 +147,9 @@ class _ChoosePlaceNameViewState extends ConsumerState { ); } - Widget _addPlaceView(ChoosePlaceViewState state) { + Widget _addPlaceButtonView(ChoosePlaceViewState state) { final enable = _textController.text.isNotEmpty && !state.addingPlace; + return Padding( padding: EdgeInsets.only(bottom: context.mediaQueryPadding.bottom + 24), child: PrimaryButton( @@ -167,6 +165,15 @@ class _ChoosePlaceNameViewState extends ConsumerState { ); } + void _observeError() { + ref.listen(choosePlaceViewStateProvider.select((state) => state.error), + (previous, next) { + if (next != null) { + showErrorSnackBar(context, next.toString()); + } + }); + } + void _observePopToPlacesListScreen() { ref.listen( choosePlaceViewStateProvider.select((state) => state.popToPlaceList), diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart index 5ed3d84c..5b3f60d3 100644 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart @@ -79,7 +79,6 @@ class ChoosePlaceViewState with _$ChoosePlaceViewState { const factory ChoosePlaceViewState({ @Default(false) addingPlace, List? suggestions, - String? placeName, Object? error, DateTime? popToPlaceList, }) = _ChoosePlaceViewState; diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart index 1cd61124..2bc9b0e7 100644 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart @@ -18,7 +18,6 @@ final _privateConstructorUsedError = UnsupportedError( mixin _$ChoosePlaceViewState { dynamic get addingPlace => throw _privateConstructorUsedError; List? get suggestions => throw _privateConstructorUsedError; - String? get placeName => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; DateTime? get popToPlaceList => throw _privateConstructorUsedError; @@ -36,7 +35,6 @@ abstract class $ChoosePlaceViewStateCopyWith<$Res> { $Res call( {dynamic addingPlace, List? suggestions, - String? placeName, Object? error, DateTime? popToPlaceList}); } @@ -57,7 +55,6 @@ class _$ChoosePlaceViewStateCopyWithImpl<$Res, $Res call({ Object? addingPlace = freezed, Object? suggestions = freezed, - Object? placeName = freezed, Object? error = freezed, Object? popToPlaceList = freezed, }) { @@ -70,10 +67,6 @@ class _$ChoosePlaceViewStateCopyWithImpl<$Res, ? _value.suggestions : suggestions // ignore: cast_nullable_to_non_nullable as List?, - placeName: freezed == placeName - ? _value.placeName - : placeName // ignore: cast_nullable_to_non_nullable - as String?, error: freezed == error ? _value.error : error, popToPlaceList: freezed == popToPlaceList ? _value.popToPlaceList @@ -94,7 +87,6 @@ abstract class _$$ChoosePlaceViewStateImplCopyWith<$Res> $Res call( {dynamic addingPlace, List? suggestions, - String? placeName, Object? error, DateTime? popToPlaceList}); } @@ -112,7 +104,6 @@ class __$$ChoosePlaceViewStateImplCopyWithImpl<$Res> $Res call({ Object? addingPlace = freezed, Object? suggestions = freezed, - Object? placeName = freezed, Object? error = freezed, Object? popToPlaceList = freezed, }) { @@ -122,10 +113,6 @@ class __$$ChoosePlaceViewStateImplCopyWithImpl<$Res> ? _value._suggestions : suggestions // ignore: cast_nullable_to_non_nullable as List?, - placeName: freezed == placeName - ? _value.placeName - : placeName // ignore: cast_nullable_to_non_nullable - as String?, error: freezed == error ? _value.error : error, popToPlaceList: freezed == popToPlaceList ? _value.popToPlaceList @@ -141,7 +128,6 @@ class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { const _$ChoosePlaceViewStateImpl( {this.addingPlace = false, final List? suggestions, - this.placeName, this.error, this.popToPlaceList}) : _suggestions = suggestions; @@ -159,8 +145,6 @@ class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { return EqualUnmodifiableListView(value); } - @override - final String? placeName; @override final Object? error; @override @@ -168,7 +152,7 @@ class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { @override String toString() { - return 'ChoosePlaceViewState(addingPlace: $addingPlace, suggestions: $suggestions, placeName: $placeName, error: $error, popToPlaceList: $popToPlaceList)'; + return 'ChoosePlaceViewState(addingPlace: $addingPlace, suggestions: $suggestions, error: $error, popToPlaceList: $popToPlaceList)'; } @override @@ -180,8 +164,6 @@ class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { .equals(other.addingPlace, addingPlace) && const DeepCollectionEquality() .equals(other._suggestions, _suggestions) && - (identical(other.placeName, placeName) || - other.placeName == placeName) && const DeepCollectionEquality().equals(other.error, error) && (identical(other.popToPlaceList, popToPlaceList) || other.popToPlaceList == popToPlaceList)); @@ -192,7 +174,6 @@ class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { runtimeType, const DeepCollectionEquality().hash(addingPlace), const DeepCollectionEquality().hash(_suggestions), - placeName, const DeepCollectionEquality().hash(error), popToPlaceList); @@ -209,7 +190,6 @@ abstract class _ChoosePlaceViewState implements ChoosePlaceViewState { const factory _ChoosePlaceViewState( {final dynamic addingPlace, final List? suggestions, - final String? placeName, final Object? error, final DateTime? popToPlaceList}) = _$ChoosePlaceViewStateImpl; @@ -218,8 +198,6 @@ abstract class _ChoosePlaceViewState implements ChoosePlaceViewState { @override List? get suggestions; @override - String? get placeName; - @override Object? get error; @override DateTime? get popToPlaceList; diff --git a/app/lib/ui/flow/geofence/places/places_list_view.dart b/app/lib/ui/flow/geofence/places/places_list_view.dart index e4924098..2fafec41 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view.dart @@ -13,6 +13,7 @@ import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_view_model import '../../../../domain/extenstions/widget_extensions.dart'; import '../../../../gen/assets.gen.dart'; +import '../../../components/error_snakebar.dart'; class PlacesListView extends ConsumerStatefulWidget { final String spaceId; @@ -39,6 +40,7 @@ class _PlacesViewState extends ConsumerState { Widget build(BuildContext context) { final state = ref.watch(placesListViewStateProvider); + _observeError(); _observeShowDeletePlaceDialog(); return AppPage(title: context.l10n.places_list_title, body: _body(state)); @@ -221,6 +223,15 @@ class _PlacesViewState extends ConsumerState { } } + void _observeError() { + ref.listen(placesListViewStateProvider.select((state) => state.error), + (previous, next) { + if (next != null) { + showErrorSnackBar(context, next.toString()); + } + }); + } + void _observeShowDeletePlaceDialog() { ref.listen( placesListViewStateProvider diff --git a/data/lib/api/place/api_place.dart b/data/lib/api/place/api_place.dart index c88a238e..f3458284 100644 --- a/data/lib/api/place/api_place.dart +++ b/data/lib/api/place/api_place.dart @@ -1,6 +1,8 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import '../../converter/time_converter.dart'; + part 'api_place.freezed.dart'; part 'api_place.g.dart'; @@ -57,15 +59,3 @@ class ApiPlaceMemberSetting with _$ApiPlaceMemberSetting { Map toFireStore(ApiPlaceMemberSetting space) => space.toJson(); } - -class TimeStampJsonConverter extends JsonConverter { - const TimeStampJsonConverter(); - - @override - DateTime fromJson(Timestamp json) { - return json.toDate(); - } - - @override - Timestamp toJson(DateTime object) => Timestamp.fromDate(object); -} diff --git a/data/lib/converter/time_converter.dart b/data/lib/converter/time_converter.dart new file mode 100644 index 00000000..dc254391 --- /dev/null +++ b/data/lib/converter/time_converter.dart @@ -0,0 +1,14 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +class TimeStampJsonConverter extends JsonConverter { + const TimeStampJsonConverter(); + + @override + DateTime fromJson(Timestamp json) { + return json.toDate(); + } + + @override + Timestamp toJson(DateTime object) => Timestamp.fromDate(object); +} From 7879b77a40b5d1484aec22f6194f9e0ee3143da3 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 26 Jun 2024 10:36:09 +0530 Subject: [PATCH 27/65] Minor fixes --- app/lib/ui/flow/home/home_screen.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index 0ae764d8..df67d590 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:style/extenstions/context_extenstions.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; import 'package:yourspace_flutter/domain/extenstions/widget_extensions.dart'; import 'package:yourspace_flutter/ui/app_route.dart'; import 'package:yourspace_flutter/ui/components/app_page.dart'; @@ -9,6 +10,7 @@ import 'package:yourspace_flutter/ui/components/resume_detector.dart'; import 'package:yourspace_flutter/ui/flow/home/home_screen_viewmodel.dart'; import 'package:yourspace_flutter/ui/flow/home/map/map_view_model.dart'; +import '../../components/permission_dialog.dart'; import 'components/home_top_bar.dart'; import 'map/map_view.dart'; From 47b366d9b543400fd29e2ab56b5d5d9e321ff20f Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 26 Jun 2024 11:12:11 +0530 Subject: [PATCH 28/65] Minor --- data/lib/service/place_service.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/lib/service/place_service.dart b/data/lib/service/place_service.dart index 0470b796..1836e2e9 100644 --- a/data/lib/service/place_service.dart +++ b/data/lib/service/place_service.dart @@ -4,8 +4,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../api/network/client.dart'; -const placeApiKey = "AIzaSyDLlL9HqzRyfVQHsNkNZjJf1ItdwvEJTOc"; - final placeServiceProvider = Provider( (ref) => PlaceService( ref.read(firestoreProvider), From d4352ffc777da776c5b0e854e70257208e0e98a1 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 26 Jun 2024 11:43:29 +0530 Subject: [PATCH 29/65] Fix place route --- app/lib/ui/flow/home/map/map_view.dart | 133 +++++++++++++------------ 1 file changed, 69 insertions(+), 64 deletions(-) diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index 128f9c90..b2b7f5a9 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -35,7 +35,7 @@ class _MapScreenState extends ConsumerState { late MapViewNotifier notifier; final Completer _controller = Completer(); final _cameraPosition = - const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); + const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); final List _markers = []; final List _places = []; @@ -102,7 +102,12 @@ class _MapScreenState extends ConsumerState { notifier.showMemberDetail(member); }, onRelocateTap: () {}, - onPlacesTap: () {}, + onPlacesTap: () { + final space = widget.space; + if (space != null) { + AppRoute.placesList(space.space.id).push(context); + } + }, onDismiss: () => notifier.onDismissMemberDetail(), onTapTimeline: () {}, ), @@ -113,7 +118,7 @@ class _MapScreenState extends ConsumerState { Widget _permissionFooter(MapViewState state) { final locationEnabled = - state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; + state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; final (title, subTitle) = _permissionFooterContent(state); return OnTapScale( @@ -164,7 +169,7 @@ class _MapScreenState extends ConsumerState { (String, String) _permissionFooterContent(MapViewState state) { final locationEnabled = - state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; + state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; String title = ''; String subTitle = ''; @@ -197,7 +202,7 @@ class _MapScreenState extends ConsumerState { final controller = await _controller.future; if (isDarkMode) { final style = - await rootBundle.loadString('assets/map/map_theme_night.json'); + await rootBundle.loadString('assets/map/map_theme_night.json'); controller.setMapStyle(style); } else { controller.setMapStyle(null); @@ -206,57 +211,57 @@ class _MapScreenState extends ConsumerState { void _observeMapCameraPosition() { ref.listen(mapViewStateProvider.select((state) => state.defaultPosition), - (previous, next) async { - if (next != null) { - final GoogleMapController controller = await _controller.future; - await controller.animateCamera(CameraUpdate.newCameraPosition(next)); - } - }); + (previous, next) async { + if (next != null) { + final GoogleMapController controller = await _controller.future; + await controller.animateCamera(CameraUpdate.newCameraPosition(next)); + } + }); } void _observeNavigation() { ref.listen( mapViewStateProvider.select((state) => state.spaceInvitationCode), - (_, next) { - if (next.isNotEmpty) { - AppRoute.inviteCode( + (_, next) { + if (next.isNotEmpty) { + AppRoute.inviteCode( code: next, spaceName: widget.space?.space.name ?? '') - .push(context); - } - }); + .push(context); + } + }); } void _observeMarkerChange() { ref.listen(mapViewStateProvider.select((state) => state.markers), - (_, next) { - if (next.isNotEmpty) { - for (final item in next) { - _buildMarker(item); - } - } - }); + (_, next) { + if (next.isNotEmpty) { + for (final item in next) { + _buildMarker(item); + } + } + }); } void _observeShowEnableLocationPrompt(BuildContext context) { ref.listen(mapViewStateProvider.select((state) => state.showLocationDialog), - (_, next) { - if (next != null) { - showDialog( - context: context, - builder: (context) { - return PermissionDialog( - title: context.l10n.enable_location_service_title, - subTitle1: context.l10n.enable_location_service_message, - onDismiss: () {}, - goToSettings: () { - openAppSettings(); - Navigator.of(context).pop(); - }, - ); + (_, next) { + if (next != null) { + showDialog( + context: context, + builder: (context) { + return PermissionDialog( + title: context.l10n.enable_location_service_title, + subTitle1: context.l10n.enable_location_service_message, + onDismiss: () {}, + goToSettings: () { + openAppSettings(); + Navigator.of(context).pop(); }, ); - } - }); + }, + ); + } + }); } void _observeMemberPlace(BuildContext context) { @@ -312,13 +317,13 @@ class _MapScreenState extends ConsumerState { } Future _mapMarker( - bool isSelected, - String userName, - ui.Image? imageUrl, - Color markerBgColor, - Color iconBgColor, - TextStyle textStyle, - ) async { + bool isSelected, + String userName, + ui.Image? imageUrl, + Color markerBgColor, + Color iconBgColor, + TextStyle textStyle, + ) async { if (imageUrl != null) { return await _userImageMarker(userName, imageUrl, isSelected, markerBgColor, iconBgColor, textStyle); @@ -329,12 +334,12 @@ class _MapScreenState extends ConsumerState { } Future _userCharMarker( - bool isSelected, - String userName, - Color markerBgColor, - Color iconBgColor, - TextStyle textStyle, - ) async { + bool isSelected, + String userName, + Color markerBgColor, + Color iconBgColor, + TextStyle textStyle, + ) async { final pictureRecorder = ui.PictureRecorder(); final canvas = Canvas(pictureRecorder); @@ -356,7 +361,7 @@ class _MapScreenState extends ConsumerState { final img = await picture.toImage(markerSize.toInt(), markerSize.toInt()); final byteData = await img.toByteData(format: ui.ImageByteFormat.png); final bitmapDescriptor = - BitmapDescriptor.fromBytes(byteData!.buffer.asUint8List()); + BitmapDescriptor.fromBytes(byteData!.buffer.asUint8List()); return bitmapDescriptor; } @@ -382,13 +387,13 @@ class _MapScreenState extends ConsumerState { } Future _userImageMarker( - String userName, - ui.Image uiImage, - bool isSelected, - Color markerBgColor, - Color iconBgColor, - TextStyle textStyle, - ) async { + String userName, + ui.Image uiImage, + bool isSelected, + Color markerBgColor, + Color iconBgColor, + TextStyle textStyle, + ) async { // Prepare the canvas to draw the rounded rectangle and the image final recorder = ui.PictureRecorder(); final canvas = ui.Canvas( @@ -418,11 +423,11 @@ class _MapScreenState extends ConsumerState { // End recording and create an image from the canvas final picture = recorder.endRecording(); final imgData = - await picture.toImage(markerSize.toInt(), markerSize.toInt()); + await picture.toImage(markerSize.toInt(), markerSize.toInt()); final data = await imgData.toByteData(format: ui.ImageByteFormat.png); final bitmapDescriptor = - BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); + BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); return bitmapDescriptor; } @@ -476,4 +481,4 @@ class _MapScreenState extends ConsumerState { }); }); } -} \ No newline at end of file +} From f9a0aa0c20bf88856b05d427bd1c5ca2544f62ae Mon Sep 17 00:00:00 2001 From: kaushik Date: Thu, 27 Jun 2024 19:03:44 +0530 Subject: [PATCH 30/65] Implement edit place screen --- app/assets/locales/app_en.arb | 15 +- app/lib/ui/app_route.dart | 14 + .../choose_place_name_view_model.dart | 2 +- .../edit/components/place_marker.dart | 52 ++ .../flow/geofence/edit/edit_place_view.dart | 529 ++++++++++++++++++ .../geofence/edit/edit_place_view_model.dart | 207 +++++++ .../edit/edit_place_view_model.freezed.dart | 462 +++++++++++++++ .../geofence/places/places_list_view.dart | 99 ++-- data/lib/api/place/api_place.dart | 2 +- data/lib/api/place/api_place.freezed.dart | 5 +- data/lib/api/place/api_place.g.dart | 2 +- data/lib/service/place_service.dart | 46 +- 12 files changed, 1383 insertions(+), 52 deletions(-) create mode 100644 app/lib/ui/flow/geofence/edit/components/place_marker.dart create mode 100644 app/lib/ui/flow/geofence/edit/edit_place_view.dart create mode 100644 app/lib/ui/flow/geofence/edit/edit_place_view_model.dart create mode 100644 app/lib/ui/flow/geofence/edit/edit_place_view_model.freezed.dart diff --git a/app/assets/locales/app_en.arb b/app/assets/locales/app_en.arb index c80fe9fc..7734f754 100644 --- a/app/assets/locales/app_en.arb +++ b/app/assets/locales/app_en.arb @@ -7,6 +7,7 @@ "common_get_started": "Get Started", "common_next": "Next", "common_yes": "Yes", + "common_save": "Save", "common_cancel": "Cancel", "common_delete": "Delete", "common_okay": "Okay", @@ -197,5 +198,17 @@ "choose_place_add_place_btn_text": "Add place", "choose_place_prompt_added_title_text": "{placeName} Added", "choose_place_prompt_sub_title_text": "You will be notified when members of your space arrive/leave this place", - "choose_place_prompt_got_it_btn_text": "Got it" + "choose_place_prompt_got_it_btn_text": "Got it", + + "@_EditPlaces": { + }, + "edit_place_title_text": "Edit place", + "edit_place_getting_address_text": "Getting Address…", + "edit_place_detail_title_text": "Place detail", + "edit_place_get_notified_title_text": "Get notified when...", + "edit_place_arrives_text": "Arrives", + "edit_place_leaves_text": "Leaves", + "edit_place_delete_place_btn_text": "Delete place", + "edit_place_only_admin_edit_text": "Only admin can edit or delete this place.", + "edit_place_delete_dialog_sub_title_text": "Are you sure you want to delete this place? This action cannot be undone." } \ No newline at end of file diff --git a/app/lib/ui/app_route.dart b/app/lib/ui/app_route.dart index 42ae5670..dc121d0d 100644 --- a/app/lib/ui/app_route.dart +++ b/app/lib/ui/app_route.dart @@ -1,9 +1,11 @@ +import 'package:data/api/place/api_place.dart'; import 'package:flutter/cupertino.dart'; import 'package:go_router/go_router.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:yourspace_flutter/ui/flow/auth/sign_in/phone/verification/phone_verification_screen.dart'; import 'package:yourspace_flutter/ui/flow/geofence/add/locate/locate_on_map_view.dart'; import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_name_view.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/edit/edit_place_view.dart'; import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_view.dart'; import 'package:yourspace_flutter/ui/flow/onboard/pick_name_screen.dart'; import 'package:yourspace_flutter/ui/flow/permission/enable_permission_view.dart'; @@ -35,6 +37,7 @@ class AppRoute { static const pathAddNewPlace = '/add-new-place'; static const pathLocateOnMap = "/locate_on_map"; static const pathChoosePlace = "/choose_place"; + static const pathEditPlace = "/edit_place"; final String path; final String? name; @@ -193,6 +196,13 @@ class AppRoute { ); } + static AppRoute editPlaceScreen(ApiPlace place) { + return AppRoute( + pathEditPlace, + builder: (_) => EditPlaceView(place: place), + ); + } + static final routes = [ GoRoute( path: intro.path, @@ -278,6 +288,10 @@ class AppRoute { GoRoute( path: pathChoosePlace, builder: (context, state) => state.widget(context), + ), + GoRoute( + path: pathEditPlace, + builder: (context, state) => state.widget(context), ) ]; } diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart index 5b3f60d3..3efd7083 100644 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart @@ -51,7 +51,7 @@ class ChoosePlaceNameViewNotifier extends StateNotifier { try { state = state.copyWith(addingPlace: true); final members = await spaceService.getMemberBySpaceId(_spaceId!); - final memberIds = members.map((member) => member.id).toList(); + final memberIds = members.map((member) => member.user_id).toList(); await placesService.addPlace( _spaceId!, diff --git a/app/lib/ui/flow/geofence/edit/components/place_marker.dart b/app/lib/ui/flow/geofence/edit/components/place_marker.dart new file mode 100644 index 00000000..1f446c5b --- /dev/null +++ b/app/lib/ui/flow/geofence/edit/components/place_marker.dart @@ -0,0 +1,52 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:style/extenstions/context_extenstions.dart'; + +import '../../../../../gen/assets.gen.dart'; + +class PlaceMarker extends StatefulWidget { + final double radius; + + const PlaceMarker({super.key, required this.radius}); + + @override + State createState() => _PlaceMarkerState(); +} + +class _PlaceMarkerState extends State { + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + AnimatedContainer( + duration: const Duration(milliseconds: 300), + width: widget.radius, + height: widget.radius, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(widget.radius), + color: context.colorScheme.primary.withOpacity(0.5), + ), + ), + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: context.colorScheme.onPrimary, + ), + child: Padding( + padding: const EdgeInsets.all(4), + child: SvgPicture.asset( + Assets.images.icLocationFeedIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.primary, + BlendMode.srcATop, + ), + ), + ), + ), + ], + ); + } +} diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view.dart b/app/lib/ui/flow/geofence/edit/edit_place_view.dart new file mode 100644 index 00000000..b6362cb0 --- /dev/null +++ b/app/lib/ui/flow/geofence/edit/edit_place_view.dart @@ -0,0 +1,529 @@ +import 'dart:math' as math; +import 'dart:math'; + +import 'package:data/api/auth/auth_models.dart'; +import 'package:data/api/place/api_place.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:style/animation/on_tap_scale.dart'; +import 'package:style/button/primary_button.dart'; +import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/indicator/progress_indicator.dart'; +import 'package:style/text/app_text_dart.dart'; +import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; +import 'package:yourspace_flutter/ui/components/app_page.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/edit/edit_place_view_model.dart'; +import 'package:yourspace_flutter/ui/flow/setting/profile/profile_view_model.dart'; + +import '../../../../domain/extenstions/widget_extensions.dart'; +import '../../../components/error_snakebar.dart'; +import '../../../components/user_profile_image.dart'; +import 'components/place_marker.dart'; + +class EditPlaceView extends ConsumerStatefulWidget { + final ApiPlace place; + + const EditPlaceView({super.key, required this.place}); + + @override + ConsumerState createState() => _EditPlaceViewState(); +} + +class _EditPlaceViewState extends ConsumerState { + late EditPlaceViewNotifier notifier; + late CameraPosition _cameraPosition; + GoogleMapController? _controller; + TextEditingController _textController = TextEditingController(); + double radiusToPixel = 0.0; + + @override + void initState() { + super.initState(); + _textController = TextEditingController(text: widget.place.name); + _cameraPosition = CameraPosition( + target: LatLng(widget.place.latitude, widget.place.longitude), + zoom: 16); + + runPostFrame(() { + notifier = ref.watch(editPlaceViewStateProvider.notifier); + notifier.loadDate(widget.place); + }); + } + + @override + Widget build(BuildContext context) { + final state = ref.watch(editPlaceViewStateProvider); + + _observeError(); + _observeMapCameraPosition(); + _observePopBack(); + _observeDeleteDialog(); + + return AppPage( + title: context.l10n.edit_place_title_text, + actions: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: state.saving + ? const AppProgressIndicator(size: AppProgressIndicatorSize.small) + : OnTapScale( + onTap: () { + notifier.onSavePlace(); + }, + child: Text( + context.l10n.common_save, + style: AppTextStyle.button.copyWith( + color: state.enableSave + ? context.colorScheme.primary + : context.colorScheme.textDisabled, + ), + ), + ), + ) + ], + body: state.loading + ? const Center( + child: AppProgressIndicator( + size: AppProgressIndicatorSize.normal, + ), + ) + : _body(state), + ); + } + + Widget _body(EditPlaceState state) { + final place = state.updatedPlace; + if (place == null) return Container(); + + return SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: 1.85, + child: _googleMapView( + place.latitude, + place.longitude, + state.isAdmin, + place.radius, + ), + ), + Visibility( + visible: state.isAdmin, + child: _radiusSliderView(place.radius), + ), + _placeDetailView(place, state), + const SizedBox(height: 40), + _placeSettingView(state), + const SizedBox(height: 40), + _deletePlaceButton(state.isAdmin, state.deleting) + ], + ), + ); + } + + Widget _googleMapView(double lat, double lng, bool isAdmin, double radius) { + return Stack( + alignment: Alignment.center, + children: [ + GoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: _cameraPosition, + gestureRecognizers: { + Factory( + () => EagerGestureRecognizer()) + }, + scrollGesturesEnabled: isAdmin, + rotateGesturesEnabled: isAdmin, + compassEnabled: false, + zoomControlsEnabled: false, + tiltGesturesEnabled: false, + myLocationButtonEnabled: false, + mapToolbarEnabled: false, + onCameraMove: (position) { + notifier.onMapCameraMove(position); + }, + ), + FutureBuilder( + future: convertZoneRadiusToPixels(LatLng(lat, lng), radius * 1.08), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData) { + final newRadius = snapshot.data; + return IgnorePointer(child: PlaceMarker(radius: newRadius!)); + } else { + return IgnorePointer(child: PlaceMarker(radius: radiusToPixel)); + } + }) + //IgnorePointer(child: PlaceMarker(radius: radiusToPixel)) + ], + ); + } + + Widget _radiusSliderView(double radius) { + String radiusText; + if (radius < 1609.34) { + radiusText = '${radius.round()} m'; + } else { + final miles = (radius / 1609.34); + radiusText = miles % 1 == 0.0 + ? '${miles.toInt()} mi' + : '${miles.toStringAsFixed(1)} mi'; + } + + return Padding( + padding: const EdgeInsets.only(right: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + child: Slider( + value: radius, + onChanged: notifier.onPlaceRadiusChanged, + min: 100, + max: 3219, + divisions: 100, + ), + ), + const SizedBox(width: 8), + Text( + radiusText, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textSecondary), + ), + ], + ), + ); + } + + Widget _placeDetailView(ApiPlace place, EditPlaceState state) { + final address = state.gettingAddress + ? context.l10n.edit_place_getting_address_text + : state.address ?? ''; + return Padding( + padding: const EdgeInsets.only(top: 24, left: 16, right: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.l10n.edit_place_detail_title_text, + style: AppTextStyle.subtitle1 + .copyWith(color: context.colorScheme.textDisabled), + ), + const SizedBox(height: 16), + _searchTextField(place.name, Icons.bookmark, state.isAdmin), + const SizedBox(height: 16), + _placeAddressView(address), + const SizedBox(height: 8), + Divider(thickness: 1, height: 1, color: context.colorScheme.outline) + ], + ), + ); + } + + Widget _searchTextField(String placeName, IconData iconData, bool isAdmin) { + return Column( + children: [ + TextField( + controller: _textController, + enabled: isAdmin, + style: AppTextStyle.subtitle3 + .copyWith(color: context.colorScheme.textPrimary), + onChanged: (value) { + notifier.onPlaceNameChanged(value.trim()); + }, + onTapOutside: (event) { + FocusManager.instance.primaryFocus?.unfocus(); + }, + decoration: InputDecoration( + prefixIcon: Padding( + padding: const EdgeInsets.only(right: 8), + child: Icon( + iconData, + color: context.colorScheme.textPrimary, + ), + ), + contentPadding: const EdgeInsets.symmetric(vertical: 0), + prefixIconConstraints: const BoxConstraints(), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(color: context.colorScheme.outline), + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: context.colorScheme.primary), + ), + ), + ), + ], + ); + } + + Widget _placeAddressView(String address) { + return Row( + children: [ + Icon( + Icons.location_on_outlined, + color: context.colorScheme.textPrimary, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + address, + style: AppTextStyle.subtitle3 + .copyWith(color: context.colorScheme.textPrimary), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ) + ], + ); + } + + Widget _placeSettingView(EditPlaceState state) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + context.l10n.edit_place_get_notified_title_text, + style: AppTextStyle.subtitle1 + .copyWith(color: context.colorScheme.textDisabled), + ), + ), + const SizedBox(height: 16), + ...state.membersInfo.map((member) { + final isLast = + state.membersInfo.indexOf(member) == state.membersInfo.length - 1; + return _memberItemView(member, state.updatedSetting, isLast); + }), + ], + ); + } + + Widget _memberItemView( + ApiUserInfo member, + ApiPlaceMemberSetting? setting, + bool isLast, + ) { + final user = member.user; + final enableArrives = setting?.arrival_alert_for.contains(user.id) ?? false; + final enableLeaves = setting?.leave_alert_for.contains(user.id) ?? false; + + return Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _memberProfileView(user), + const Spacer(), + Column( + children: [ + _toggleSwitch( + title: context.l10n.edit_place_arrives_text, + enable: enableArrives, + onChanged: (value) { + notifier.onToggleArrives(user.id, value); + }, + ), + const SizedBox(height: 8), + _toggleSwitch( + title: context.l10n.edit_place_leaves_text, + enable: enableLeaves, + onChanged: (value) { + notifier.onToggleLeaves(user.id, value); + }, + ), + ], + ), + ], + ), + ), + Visibility( + visible: !isLast, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: Divider( + thickness: 1, height: 1, color: context.colorScheme.outline), + ), + ) + ], + ); + } + + Widget _memberProfileView(ApiUser user) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ImageAvatar( + size: 40, + imageUrl: user.profile_image, + initials: user.firstChar, + ), + const SizedBox(width: 16), + Text( + user.fullName, + style: AppTextStyle.subtitle2 + .copyWith(color: context.colorScheme.textPrimary), + ), + ], + ), + ); + } + + Widget _toggleSwitch({ + required String title, + required bool enable, + required Function(bool) onChanged, + }) { + return Row( + children: [ + Text( + context.l10n.edit_place_leaves_text, + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.textDisabled), + ), + const SizedBox(width: 16), + Switch(value: enable, onChanged: onChanged) + ], + ); + } + + Widget _deletePlaceButton(bool isAdmin, bool isDeleting) { + return Center( + child: Padding( + padding: EdgeInsets.only( + left: 16, + right: 16, + bottom: context.mediaQueryPadding.bottom + 24, + ), + child: Column( + children: [ + isAdmin + ? PrimaryButton( + progress: isDeleting, + context.l10n.edit_place_delete_place_btn_text, + background: context.colorScheme.containerLow, + foreground: context.colorScheme.alert, + onPressed: notifier.onTapDeletePlaceBtn, + ) + : Text( + context.l10n.edit_place_only_admin_edit_text, + style: AppTextStyle.body2 + .copyWith(color: context.colorScheme.textSecondary), + ) + ], + ), + ), + ); + } + + void _onMapCreated(GoogleMapController controller) { + _controller = controller; + } + + void _observeError() { + ref.listen(editProfileViewStateProvider.select((state) => state.error), + (previous, next) { + if (next != null) { + showErrorSnackBar(context, next.toString()); + } + }); + } + + void _observeMapCameraPosition() { + ref.listen(editPlaceViewStateProvider.select((state) => state.updatedPlace), + (previous, next) async { + if (next != null) { + final latLng = LatLng(next.latitude, next.longitude); + final zoom = getZoomLevel(next.radius); + await _controller + ?.animateCamera(CameraUpdate.newLatLngZoom(latLng, zoom)); + } + }); + } + + void _observePopBack() { + ref.listen(editPlaceViewStateProvider.select((state) => state.popToBack), + (_, next) { + if (next != null) { + context.pop(); + } + }); + } + + double getZoomLevel(double radius) { + double scale = radius / 200; + double zoomLevel = 16 - math.log(scale) / math.log(2); + return zoomLevel; + } + + Future convertZoneRadiusToPixels( + LatLng latLang, + double radius, + ) async { + const double earthRadius = 6378100.0; + double lat1 = radius / earthRadius; + double lng1 = radius / (earthRadius * cos(pi * latLang.latitude / 180)); + + double lat2 = latLang.latitude + lat1 * 180 / pi; + double lng2 = latLang.longitude + lng1 * 180 / pi; + + final p1 = await _controller + ?.getScreenCoordinate(LatLng(latLang.latitude, latLang.longitude)); + final p2 = await _controller?.getScreenCoordinate(LatLng(lat2, lng2)); + + setState(() { + radiusToPixel = (p1!.x - p2!.x).abs().toDouble(); + }); + return (p1!.x - p2!.x).abs().toDouble(); + } + + void _observeDeleteDialog() { + ref.listen( + editPlaceViewStateProvider.select((state) => state.showDeleteDialog), + (_, next) { + if (next != null) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + content: Text( + context.l10n.edit_place_delete_dialog_sub_title_text, + ), + actions: [ + TextButton( + child: Text( + context.l10n.common_cancel, + style: AppTextStyle.button + .copyWith(color: context.colorScheme.textSecondary), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: Text( + context.l10n.common_delete, + style: AppTextStyle.button + .copyWith(color: context.colorScheme.alert), + ), + onPressed: () { + notifier.onPlaceDelete(); + Navigator.of(context).pop(); + }, + ), + ], + ); + }); + } + }); + } +} diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart b/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart new file mode 100644 index 00000000..02bda165 --- /dev/null +++ b/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart @@ -0,0 +1,207 @@ +import 'package:data/api/auth/auth_models.dart'; +import 'package:data/api/place/api_place.dart'; +import 'package:data/log/logger.dart'; +import 'package:data/service/place_service.dart'; +import 'package:data/service/space_service.dart'; +import 'package:data/storage/app_preferences.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:yourspace_flutter/domain/extenstions/lat_lng_extenstion.dart'; + +part 'edit_place_view_model.freezed.dart'; + +final editPlaceViewStateProvider = + StateNotifierProvider.autoDispose( + (ref) { + return EditPlaceViewNotifier( + ref.read(currentUserPod), + ref.read(placeServiceProvider), + ref.read(spaceServiceProvider), + ); +}); + +class EditPlaceViewNotifier extends StateNotifier { + final ApiUser? _currentUser; + final PlaceService placeService; + final SpaceService spaceService; + + ApiPlace? _place; + ApiPlaceMemberSetting? _setting; + + EditPlaceViewNotifier(this._currentUser, this.placeService, this.spaceService) + : super(const EditPlaceState()); + + void loadDate(ApiPlace place) async { + if (state.loading) return; + try { + state = state.copyWith(loading: true); + + final spaceInfo = await spaceService.getSpaceInfo(place.space_id); + final setting = await placeService.getPlaceMemberSetting( + place.id, place.space_id, _currentUser!.id); + + final membersInfo = spaceInfo?.members + .where((member) => member.user.id != _currentUser.id) + .toList(); + _place = place; + _setting = setting; + state = state.copyWith( + updatedPlace: place, + membersInfo: membersInfo ?? [], + updatedSetting: setting, + isAdmin: place.created_by == _currentUser.id, + loading: false, + ); + getAddress(place.latitude, place.longitude); + } catch (error, stack) { + state = state.copyWith(loading: false, error: error); + logger.e( + 'EditPlaceViewNotifier: Error while getting place setting', + error: error, + stackTrace: stack, + ); + } + } + + void getAddress(double latitude, double longitude) async { + if (state.gettingAddress) return; + + state = state.copyWith(gettingAddress: true); + final latLng = LatLng(latitude, longitude); + final address = await latLng.getAddressFromLocation(); + state = state.copyWith(address: address, gettingAddress: false); + } + + void onMapCameraMove(CameraPosition position) { + if (state.updatedPlace == null) return; + + final target = position.target; + final updatePlace = state.updatedPlace + ?.copyWith(latitude: target.latitude, longitude: target.longitude); + + state = state.copyWith(updatedPlace: updatePlace); + getAddress(target.latitude, target.longitude); + enableSaveBtn(); + } + + void onToggleArrives(String userId, bool arrives) { + final arrivesList = + List.from(state.updatedSetting?.arrival_alert_for ?? []); + if (arrivesList.isNotEmpty) { + if (arrives) { + arrivesList.add(userId); + } else { + arrivesList.remove(userId); + } + final updatedSettings = + state.updatedSetting?.copyWith(arrival_alert_for: arrivesList); + state = state.copyWith(updatedSetting: updatedSettings); + } + enableSaveBtn(); + } + + void onPlaceNameChanged(String value) { + final updatedPlace = state.updatedPlace?.copyWith(name: value); + state = state.copyWith(updatedPlace: updatedPlace); + } + + void onToggleLeaves(String userId, bool leaves) { + final leaveList = + List.from(state.updatedSetting?.leave_alert_for ?? []); + if (leaveList.isNotEmpty) { + if (leaves) { + leaveList.add(userId); + } else { + leaveList.remove(userId); + } + final updatedSettings = + state.updatedSetting?.copyWith(leave_alert_for: leaveList); + state = state.copyWith(updatedSetting: updatedSettings); + } + } + + void onPlaceRadiusChanged(double value) { + if (state.updatedPlace == null) return; + final updatePlace = state.updatedPlace?.copyWith(radius: value); + state = state.copyWith(updatedPlace: updatePlace); + enableSaveBtn(); + } + + void enableSaveBtn() { + final isChanged = state.updatedPlace != _place || + (_setting != null && state.updatedSetting != _setting); + state = state.copyWith(enableSave: isChanged); + } + + void onSavePlace() async { + if (state.saving && + state.updatedSetting == null && + state.updatedPlace == null) return; + + try { + state = state.copyWith(saving: true, error: null); + final updatedPlace = state.updatedPlace!; + final updatedSetting = state.updatedSetting!; + if (updatedPlace != _place) { + await placeService.updatePlace(updatedPlace); + } + if (updatedSetting != _setting) { + await placeService.updatePlaceSetting( + updatedPlace.space_id, + updatedPlace.id, + _currentUser!.id, + updatedSetting, + ); + } + state = state.copyWith(saving: false, popToBack: DateTime.now()); + } catch (error, stack) { + state = state.copyWith(saving: false, error: error); + logger.e( + 'EditPlaceViewNotifier: Error while saving place', + error: error, + stackTrace: stack, + ); + } + } + + void onTapDeletePlaceBtn() { + state = state.copyWith(showDeleteDialog: DateTime.now()); + } + + void onPlaceDelete() async { + if (_place == null) return; + try { + state = state.copyWith(deleting: true, error: null); + await placeService.deletePlace(_place!.space_id, _place!.id); + state = state.copyWith(deleting: false, popToBack: DateTime.now()); + } catch (error, stack) { + state = state.copyWith(error: error, deleting: false); + logger.e( + "EditPlaceViewNotifier: Error while deleting place", + error: error, + stackTrace: stack, + ); + } + } +} + +@freezed +class EditPlaceState with _$EditPlaceState { + const factory EditPlaceState({ + @Default(false) bool loading, + @Default(false) bool isAdmin, + @Default(false) bool enableSave, + @Default(false) bool saving, + @Default(false) bool deleting, + @Default(false) bool gettingAddress, + String? placeId, + ApiPlace? updatedPlace, + ApiPlaceMemberSetting? updatedSetting, + @Default([]) List membersInfo, + String? address, + Object? error, + DateTime? popToBack, + DateTime? showDeleteDialog, + }) = _EditPlaceState; +} diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view_model.freezed.dart b/app/lib/ui/flow/geofence/edit/edit_place_view_model.freezed.dart new file mode 100644 index 00000000..1a427fb4 --- /dev/null +++ b/app/lib/ui/flow/geofence/edit/edit_place_view_model.freezed.dart @@ -0,0 +1,462 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'edit_place_view_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$EditPlaceState { + bool get loading => throw _privateConstructorUsedError; + bool get isAdmin => throw _privateConstructorUsedError; + bool get enableSave => throw _privateConstructorUsedError; + bool get saving => throw _privateConstructorUsedError; + bool get deleting => throw _privateConstructorUsedError; + bool get gettingAddress => throw _privateConstructorUsedError; + String? get placeId => throw _privateConstructorUsedError; + ApiPlace? get updatedPlace => throw _privateConstructorUsedError; + ApiPlaceMemberSetting? get updatedSetting => + throw _privateConstructorUsedError; + List get membersInfo => throw _privateConstructorUsedError; + String? get address => throw _privateConstructorUsedError; + Object? get error => throw _privateConstructorUsedError; + DateTime? get popToBack => throw _privateConstructorUsedError; + DateTime? get showDeleteDialog => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $EditPlaceStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $EditPlaceStateCopyWith<$Res> { + factory $EditPlaceStateCopyWith( + EditPlaceState value, $Res Function(EditPlaceState) then) = + _$EditPlaceStateCopyWithImpl<$Res, EditPlaceState>; + @useResult + $Res call( + {bool loading, + bool isAdmin, + bool enableSave, + bool saving, + bool deleting, + bool gettingAddress, + String? placeId, + ApiPlace? updatedPlace, + ApiPlaceMemberSetting? updatedSetting, + List membersInfo, + String? address, + Object? error, + DateTime? popToBack, + DateTime? showDeleteDialog}); + + $ApiPlaceCopyWith<$Res>? get updatedPlace; + $ApiPlaceMemberSettingCopyWith<$Res>? get updatedSetting; +} + +/// @nodoc +class _$EditPlaceStateCopyWithImpl<$Res, $Val extends EditPlaceState> + implements $EditPlaceStateCopyWith<$Res> { + _$EditPlaceStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = null, + Object? isAdmin = null, + Object? enableSave = null, + Object? saving = null, + Object? deleting = null, + Object? gettingAddress = null, + Object? placeId = freezed, + Object? updatedPlace = freezed, + Object? updatedSetting = freezed, + Object? membersInfo = null, + Object? address = freezed, + Object? error = freezed, + Object? popToBack = freezed, + Object? showDeleteDialog = freezed, + }) { + return _then(_value.copyWith( + loading: null == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as bool, + isAdmin: null == isAdmin + ? _value.isAdmin + : isAdmin // ignore: cast_nullable_to_non_nullable + as bool, + enableSave: null == enableSave + ? _value.enableSave + : enableSave // ignore: cast_nullable_to_non_nullable + as bool, + saving: null == saving + ? _value.saving + : saving // ignore: cast_nullable_to_non_nullable + as bool, + deleting: null == deleting + ? _value.deleting + : deleting // ignore: cast_nullable_to_non_nullable + as bool, + gettingAddress: null == gettingAddress + ? _value.gettingAddress + : gettingAddress // ignore: cast_nullable_to_non_nullable + as bool, + placeId: freezed == placeId + ? _value.placeId + : placeId // ignore: cast_nullable_to_non_nullable + as String?, + updatedPlace: freezed == updatedPlace + ? _value.updatedPlace + : updatedPlace // ignore: cast_nullable_to_non_nullable + as ApiPlace?, + updatedSetting: freezed == updatedSetting + ? _value.updatedSetting + : updatedSetting // ignore: cast_nullable_to_non_nullable + as ApiPlaceMemberSetting?, + membersInfo: null == membersInfo + ? _value.membersInfo + : membersInfo // ignore: cast_nullable_to_non_nullable + as List, + address: freezed == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String?, + error: freezed == error ? _value.error : error, + popToBack: freezed == popToBack + ? _value.popToBack + : popToBack // ignore: cast_nullable_to_non_nullable + as DateTime?, + showDeleteDialog: freezed == showDeleteDialog + ? _value.showDeleteDialog + : showDeleteDialog // ignore: cast_nullable_to_non_nullable + as DateTime?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ApiPlaceCopyWith<$Res>? get updatedPlace { + if (_value.updatedPlace == null) { + return null; + } + + return $ApiPlaceCopyWith<$Res>(_value.updatedPlace!, (value) { + return _then(_value.copyWith(updatedPlace: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $ApiPlaceMemberSettingCopyWith<$Res>? get updatedSetting { + if (_value.updatedSetting == null) { + return null; + } + + return $ApiPlaceMemberSettingCopyWith<$Res>(_value.updatedSetting!, + (value) { + return _then(_value.copyWith(updatedSetting: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$EditPlaceStateImplCopyWith<$Res> + implements $EditPlaceStateCopyWith<$Res> { + factory _$$EditPlaceStateImplCopyWith(_$EditPlaceStateImpl value, + $Res Function(_$EditPlaceStateImpl) then) = + __$$EditPlaceStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {bool loading, + bool isAdmin, + bool enableSave, + bool saving, + bool deleting, + bool gettingAddress, + String? placeId, + ApiPlace? updatedPlace, + ApiPlaceMemberSetting? updatedSetting, + List membersInfo, + String? address, + Object? error, + DateTime? popToBack, + DateTime? showDeleteDialog}); + + @override + $ApiPlaceCopyWith<$Res>? get updatedPlace; + @override + $ApiPlaceMemberSettingCopyWith<$Res>? get updatedSetting; +} + +/// @nodoc +class __$$EditPlaceStateImplCopyWithImpl<$Res> + extends _$EditPlaceStateCopyWithImpl<$Res, _$EditPlaceStateImpl> + implements _$$EditPlaceStateImplCopyWith<$Res> { + __$$EditPlaceStateImplCopyWithImpl( + _$EditPlaceStateImpl _value, $Res Function(_$EditPlaceStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? loading = null, + Object? isAdmin = null, + Object? enableSave = null, + Object? saving = null, + Object? deleting = null, + Object? gettingAddress = null, + Object? placeId = freezed, + Object? updatedPlace = freezed, + Object? updatedSetting = freezed, + Object? membersInfo = null, + Object? address = freezed, + Object? error = freezed, + Object? popToBack = freezed, + Object? showDeleteDialog = freezed, + }) { + return _then(_$EditPlaceStateImpl( + loading: null == loading + ? _value.loading + : loading // ignore: cast_nullable_to_non_nullable + as bool, + isAdmin: null == isAdmin + ? _value.isAdmin + : isAdmin // ignore: cast_nullable_to_non_nullable + as bool, + enableSave: null == enableSave + ? _value.enableSave + : enableSave // ignore: cast_nullable_to_non_nullable + as bool, + saving: null == saving + ? _value.saving + : saving // ignore: cast_nullable_to_non_nullable + as bool, + deleting: null == deleting + ? _value.deleting + : deleting // ignore: cast_nullable_to_non_nullable + as bool, + gettingAddress: null == gettingAddress + ? _value.gettingAddress + : gettingAddress // ignore: cast_nullable_to_non_nullable + as bool, + placeId: freezed == placeId + ? _value.placeId + : placeId // ignore: cast_nullable_to_non_nullable + as String?, + updatedPlace: freezed == updatedPlace + ? _value.updatedPlace + : updatedPlace // ignore: cast_nullable_to_non_nullable + as ApiPlace?, + updatedSetting: freezed == updatedSetting + ? _value.updatedSetting + : updatedSetting // ignore: cast_nullable_to_non_nullable + as ApiPlaceMemberSetting?, + membersInfo: null == membersInfo + ? _value._membersInfo + : membersInfo // ignore: cast_nullable_to_non_nullable + as List, + address: freezed == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String?, + error: freezed == error ? _value.error : error, + popToBack: freezed == popToBack + ? _value.popToBack + : popToBack // ignore: cast_nullable_to_non_nullable + as DateTime?, + showDeleteDialog: freezed == showDeleteDialog + ? _value.showDeleteDialog + : showDeleteDialog // ignore: cast_nullable_to_non_nullable + as DateTime?, + )); + } +} + +/// @nodoc + +class _$EditPlaceStateImpl implements _EditPlaceState { + const _$EditPlaceStateImpl( + {this.loading = false, + this.isAdmin = false, + this.enableSave = false, + this.saving = false, + this.deleting = false, + this.gettingAddress = false, + this.placeId, + this.updatedPlace, + this.updatedSetting, + final List membersInfo = const [], + this.address, + this.error, + this.popToBack, + this.showDeleteDialog}) + : _membersInfo = membersInfo; + + @override + @JsonKey() + final bool loading; + @override + @JsonKey() + final bool isAdmin; + @override + @JsonKey() + final bool enableSave; + @override + @JsonKey() + final bool saving; + @override + @JsonKey() + final bool deleting; + @override + @JsonKey() + final bool gettingAddress; + @override + final String? placeId; + @override + final ApiPlace? updatedPlace; + @override + final ApiPlaceMemberSetting? updatedSetting; + final List _membersInfo; + @override + @JsonKey() + List get membersInfo { + if (_membersInfo is EqualUnmodifiableListView) return _membersInfo; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_membersInfo); + } + + @override + final String? address; + @override + final Object? error; + @override + final DateTime? popToBack; + @override + final DateTime? showDeleteDialog; + + @override + String toString() { + return 'EditPlaceState(loading: $loading, isAdmin: $isAdmin, enableSave: $enableSave, saving: $saving, deleting: $deleting, gettingAddress: $gettingAddress, placeId: $placeId, updatedPlace: $updatedPlace, updatedSetting: $updatedSetting, membersInfo: $membersInfo, address: $address, error: $error, popToBack: $popToBack, showDeleteDialog: $showDeleteDialog)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$EditPlaceStateImpl && + (identical(other.loading, loading) || other.loading == loading) && + (identical(other.isAdmin, isAdmin) || other.isAdmin == isAdmin) && + (identical(other.enableSave, enableSave) || + other.enableSave == enableSave) && + (identical(other.saving, saving) || other.saving == saving) && + (identical(other.deleting, deleting) || + other.deleting == deleting) && + (identical(other.gettingAddress, gettingAddress) || + other.gettingAddress == gettingAddress) && + (identical(other.placeId, placeId) || other.placeId == placeId) && + (identical(other.updatedPlace, updatedPlace) || + other.updatedPlace == updatedPlace) && + (identical(other.updatedSetting, updatedSetting) || + other.updatedSetting == updatedSetting) && + const DeepCollectionEquality() + .equals(other._membersInfo, _membersInfo) && + (identical(other.address, address) || other.address == address) && + const DeepCollectionEquality().equals(other.error, error) && + (identical(other.popToBack, popToBack) || + other.popToBack == popToBack) && + (identical(other.showDeleteDialog, showDeleteDialog) || + other.showDeleteDialog == showDeleteDialog)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + loading, + isAdmin, + enableSave, + saving, + deleting, + gettingAddress, + placeId, + updatedPlace, + updatedSetting, + const DeepCollectionEquality().hash(_membersInfo), + address, + const DeepCollectionEquality().hash(error), + popToBack, + showDeleteDialog); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$EditPlaceStateImplCopyWith<_$EditPlaceStateImpl> get copyWith => + __$$EditPlaceStateImplCopyWithImpl<_$EditPlaceStateImpl>( + this, _$identity); +} + +abstract class _EditPlaceState implements EditPlaceState { + const factory _EditPlaceState( + {final bool loading, + final bool isAdmin, + final bool enableSave, + final bool saving, + final bool deleting, + final bool gettingAddress, + final String? placeId, + final ApiPlace? updatedPlace, + final ApiPlaceMemberSetting? updatedSetting, + final List membersInfo, + final String? address, + final Object? error, + final DateTime? popToBack, + final DateTime? showDeleteDialog}) = _$EditPlaceStateImpl; + + @override + bool get loading; + @override + bool get isAdmin; + @override + bool get enableSave; + @override + bool get saving; + @override + bool get deleting; + @override + bool get gettingAddress; + @override + String? get placeId; + @override + ApiPlace? get updatedPlace; + @override + ApiPlaceMemberSetting? get updatedSetting; + @override + List get membersInfo; + @override + String? get address; + @override + Object? get error; + @override + DateTime? get popToBack; + @override + DateTime? get showDeleteDialog; + @override + @JsonKey(ignore: true) + _$$EditPlaceStateImplCopyWith<_$EditPlaceStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/app/lib/ui/flow/geofence/places/places_list_view.dart b/app/lib/ui/flow/geofence/places/places_list_view.dart index 2fafec41..98a10599 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view.dart @@ -80,6 +80,7 @@ class _PlacesViewState extends ConsumerState { placeName: item, icon: _getPlacesIcon(item), isSuggestion: true, + onTap: () {}, onDeletePlace: () {}, ); }, @@ -138,6 +139,9 @@ class _PlacesViewState extends ConsumerState { icon: icon, allowDelete: allowDelete, isDeleting: isDeleting, + onTap: () { + AppRoute.editPlaceScreen(item).push(context); + }, onDeletePlace: () { notifier.onClickDeletePlace(item); }, @@ -150,57 +154,62 @@ class _PlacesViewState extends ConsumerState { bool isSuggestion = false, bool allowDelete = false, bool isDeleting = false, + required VoidCallback onTap, required VoidCallback onDeletePlace, }) { final enabled = !isSuggestion && allowDelete; - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - height: 36, - width: 36, - decoration: BoxDecoration( - color: context.colorScheme.containerLowOnSurface, - borderRadius: BorderRadius.circular(8), - ), - child: Center( - child: SvgPicture.asset( - icon, - colorFilter: ColorFilter.mode( - context.colorScheme.textPrimary, - BlendMode.srcATop, + return OnTapScale( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + height: 36, + width: 36, + decoration: BoxDecoration( + color: context.colorScheme.containerLowOnSurface, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: SvgPicture.asset( + icon, + colorFilter: ColorFilter.mode( + context.colorScheme.textPrimary, + BlendMode.srcATop, + ), ), ), ), - ), - const SizedBox(width: 16), - Expanded( - child: Text( - placeName, - style: AppTextStyle.subtitle3 - .copyWith(color: context.colorScheme.textPrimary), - overflow: TextOverflow.ellipsis, + const SizedBox(width: 16), + Expanded( + child: Text( + placeName, + style: AppTextStyle.subtitle3 + .copyWith(color: context.colorScheme.textPrimary), + overflow: TextOverflow.ellipsis, + ), ), - ), - (isDeleting) - ? const AppProgressIndicator(size: AppProgressIndicatorSize.small) - : Visibility( - visible: enabled, - child: OnTapScale( - onTap: onDeletePlace, - child: SvgPicture.asset( - Assets.images.icCloseIcon, - colorFilter: ColorFilter.mode( - context.colorScheme.textPrimary, - BlendMode.srcATop, + (isDeleting) + ? const AppProgressIndicator( + size: AppProgressIndicatorSize.small) + : Visibility( + visible: enabled, + child: OnTapScale( + onTap: onDeletePlace, + child: SvgPicture.asset( + Assets.images.icCloseIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.textPrimary, + BlendMode.srcATop, + ), ), ), ), - ), - ], + ], + ), ), ); } @@ -225,11 +234,11 @@ class _PlacesViewState extends ConsumerState { void _observeError() { ref.listen(placesListViewStateProvider.select((state) => state.error), - (previous, next) { - if (next != null) { - showErrorSnackBar(context, next.toString()); - } - }); + (previous, next) { + if (next != null) { + showErrorSnackBar(context, next.toString()); + } + }); } void _observeShowDeletePlaceDialog() { diff --git a/data/lib/api/place/api_place.dart b/data/lib/api/place/api_place.dart index f3458284..5c797d27 100644 --- a/data/lib/api/place/api_place.dart +++ b/data/lib/api/place/api_place.dart @@ -41,7 +41,7 @@ class ApiPlaceMemberSetting with _$ApiPlaceMemberSetting { const factory ApiPlaceMemberSetting({ required String user_id, required String place_id, - required bool alert_enabled, + @Default(false) bool alert_enabled, required List arrival_alert_for, required List leave_alert_for, }) = _ApiPlaceMemberSetting; diff --git a/data/lib/api/place/api_place.freezed.dart b/data/lib/api/place/api_place.freezed.dart index d3a28d3d..328a5e25 100644 --- a/data/lib/api/place/api_place.freezed.dart +++ b/data/lib/api/place/api_place.freezed.dart @@ -449,7 +449,7 @@ class _$ApiPlaceMemberSettingImpl extends _ApiPlaceMemberSetting { const _$ApiPlaceMemberSettingImpl( {required this.user_id, required this.place_id, - required this.alert_enabled, + this.alert_enabled = false, required final List arrival_alert_for, required final List leave_alert_for}) : _arrival_alert_for = arrival_alert_for, @@ -464,6 +464,7 @@ class _$ApiPlaceMemberSettingImpl extends _ApiPlaceMemberSetting { @override final String place_id; @override + @JsonKey() final bool alert_enabled; final List _arrival_alert_for; @override @@ -532,7 +533,7 @@ abstract class _ApiPlaceMemberSetting extends ApiPlaceMemberSetting { const factory _ApiPlaceMemberSetting( {required final String user_id, required final String place_id, - required final bool alert_enabled, + final bool alert_enabled, required final List arrival_alert_for, required final List leave_alert_for}) = _$ApiPlaceMemberSettingImpl; diff --git a/data/lib/api/place/api_place.g.dart b/data/lib/api/place/api_place.g.dart index 247e37c4..519dd28c 100644 --- a/data/lib/api/place/api_place.g.dart +++ b/data/lib/api/place/api_place.g.dart @@ -49,7 +49,7 @@ _$ApiPlaceMemberSettingImpl _$$ApiPlaceMemberSettingImplFromJson( _$ApiPlaceMemberSettingImpl( user_id: json['user_id'] as String, place_id: json['place_id'] as String, - alert_enabled: json['alert_enabled'] as bool, + alert_enabled: json['alert_enabled'] as bool? ?? false, arrival_alert_for: (json['arrival_alert_for'] as List) .map((e) => e as String) .toList(), diff --git a/data/lib/service/place_service.dart b/data/lib/service/place_service.dart index 1836e2e9..d69e1dd1 100644 --- a/data/lib/service/place_service.dart +++ b/data/lib/service/place_service.dart @@ -32,6 +32,19 @@ class PlaceService { .toList()); } + Future getPlace(String placeId) async { + final querySnapshot = await _spaceRef.firestore + .collectionGroup('space_places') + .where('id', isEqualTo: placeId) + .limit(1) + .get(); + + if (querySnapshot.docs.isNotEmpty) { + return querySnapshot.docs.first.data() as ApiPlace; + } + return null; + } + Future deletePlace(String spaceId, String placeId) async { await spacePlacesRef(spaceId).doc(placeId).delete(); } @@ -44,7 +57,6 @@ class PlaceService { String createdBy, List spaceMemberIds, ) async { - final placeDoc = spacePlacesRef(spaceId).doc(); final place = ApiPlace( @@ -76,4 +88,36 @@ class PlaceService { .set(setting.toJson()); } } + + Future getPlaceMemberSetting( + String placeId, + String spaceId, + String userId, + ) async { + final setting = await spacePlacesSettingsRef(spaceId, placeId) + .where("user_id", isEqualTo: userId) + .limit(1) + .get(); + + if (setting.docs.isNotEmpty) { + return ApiPlaceMemberSetting.fromJson( + setting.docs.first.data() as Map); + } + return null; + } + + Future updatePlaceSetting( + String spaceId, + String placeId, + String userId, + ApiPlaceMemberSetting setting, + ) async { + await spacePlacesSettingsRef(spaceId, placeId).doc(userId).set( + setting.toJson(), + ); + } + + Future updatePlace(ApiPlace place) async { + await spacePlacesRef(place.space_id).doc(place.id).set(place.toJson()); + } } From 26fc47de1619222b3606de3f974e90037fef4152 Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 28 Jun 2024 12:36:07 +0530 Subject: [PATCH 31/65] Fix marker radius with map zoom in and out --- .../edit/components/place_marker.dart | 21 ++++++---- .../flow/geofence/edit/edit_place_view.dart | 41 ++++++++----------- .../geofence/edit/edit_place_view_model.dart | 3 +- .../edit/edit_place_view_model.freezed.dart | 23 ++++++++++- 4 files changed, 55 insertions(+), 33 deletions(-) diff --git a/app/lib/ui/flow/geofence/edit/components/place_marker.dart b/app/lib/ui/flow/geofence/edit/components/place_marker.dart index 1f446c5b..2a8016a3 100644 --- a/app/lib/ui/flow/geofence/edit/components/place_marker.dart +++ b/app/lib/ui/flow/geofence/edit/components/place_marker.dart @@ -1,4 +1,5 @@ import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:style/extenstions/context_extenstions.dart'; @@ -19,13 +20,19 @@ class _PlaceMarkerState extends State { return Stack( alignment: Alignment.center, children: [ - AnimatedContainer( - duration: const Duration(milliseconds: 300), - width: widget.radius, - height: widget.radius, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(widget.radius), - color: context.colorScheme.primary.withOpacity(0.5), + ClipRect( + child: OverflowBox( + maxHeight: widget.radius, + maxWidth: widget.radius, + child: AnimatedContainer( + duration: const Duration(milliseconds: 300), + width: widget.radius, + height: widget.radius, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(widget.radius), + color: context.colorScheme.primary.withOpacity(0.5), + ), + ), ), ), Container( diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view.dart b/app/lib/ui/flow/geofence/edit/edit_place_view.dart index b6362cb0..f1c0e4c0 100644 --- a/app/lib/ui/flow/geofence/edit/edit_place_view.dart +++ b/app/lib/ui/flow/geofence/edit/edit_place_view.dart @@ -38,7 +38,8 @@ class _EditPlaceViewState extends ConsumerState { late CameraPosition _cameraPosition; GoogleMapController? _controller; TextEditingController _textController = TextEditingController(); - double radiusToPixel = 0.0; + double _radiusToPixel = 0.0; + double _previousZoom = 0.0; @override void initState() { @@ -57,9 +58,11 @@ class _EditPlaceViewState extends ConsumerState { @override Widget build(BuildContext context) { final state = ref.watch(editPlaceViewStateProvider); + final latLng = LatLng(state.updatedPlace?.latitude ?? 0.0, + state.updatedPlace?.longitude ?? 0.0); _observeError(); - _observeMapCameraPosition(); + _observeMapCameraPosition(latLng); _observePopBack(); _observeDeleteDialog(); @@ -127,6 +130,7 @@ class _EditPlaceViewState extends ConsumerState { } Widget _googleMapView(double lat, double lng, bool isAdmin, double radius) { + _convertZoneRadiusToPixels(LatLng(lat, lng), radius * 1.07); return Stack( alignment: Alignment.center, children: [ @@ -148,18 +152,7 @@ class _EditPlaceViewState extends ConsumerState { notifier.onMapCameraMove(position); }, ), - FutureBuilder( - future: convertZoneRadiusToPixels(LatLng(lat, lng), radius * 1.08), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - final newRadius = snapshot.data; - return IgnorePointer(child: PlaceMarker(radius: newRadius!)); - } else { - return IgnorePointer(child: PlaceMarker(radius: radiusToPixel)); - } - }) - //IgnorePointer(child: PlaceMarker(radius: radiusToPixel)) + IgnorePointer(child: PlaceMarker(radius: _radiusToPixel)) ], ); } @@ -189,9 +182,8 @@ class _EditPlaceViewState extends ConsumerState { divisions: 100, ), ), - const SizedBox(width: 8), Text( - radiusText, + radiusText.trim(), style: AppTextStyle.caption .copyWith(color: context.colorScheme.textSecondary), ), @@ -438,12 +430,11 @@ class _EditPlaceViewState extends ConsumerState { }); } - void _observeMapCameraPosition() { - ref.listen(editPlaceViewStateProvider.select((state) => state.updatedPlace), + void _observeMapCameraPosition(LatLng latLng) { + ref.listen(editPlaceViewStateProvider.select((state) => state.radius), (previous, next) async { if (next != null) { - final latLng = LatLng(next.latitude, next.longitude); - final zoom = getZoomLevel(next.radius); + final zoom = _getZoomLevel(next); await _controller ?.animateCamera(CameraUpdate.newLatLngZoom(latLng, zoom)); } @@ -459,16 +450,18 @@ class _EditPlaceViewState extends ConsumerState { }); } - double getZoomLevel(double radius) { + double _getZoomLevel(double radius) { double scale = radius / 200; double zoomLevel = 16 - math.log(scale) / math.log(2); return zoomLevel; } - Future convertZoneRadiusToPixels( + void _convertZoneRadiusToPixels( LatLng latLang, double radius, ) async { + final zoom = await _controller?.getZoomLevel(); + if (zoom == _previousZoom) return; const double earthRadius = 6378100.0; double lat1 = radius / earthRadius; double lng1 = radius / (earthRadius * cos(pi * latLang.latitude / 180)); @@ -481,9 +474,9 @@ class _EditPlaceViewState extends ConsumerState { final p2 = await _controller?.getScreenCoordinate(LatLng(lat2, lng2)); setState(() { - radiusToPixel = (p1!.x - p2!.x).abs().toDouble(); + _previousZoom = zoom!; + _radiusToPixel = (p1!.x - p2!.x).abs().toDouble(); }); - return (p1!.x - p2!.x).abs().toDouble(); } void _observeDeleteDialog() { diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart b/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart index 02bda165..f1a5966b 100644 --- a/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart +++ b/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart @@ -124,7 +124,7 @@ class EditPlaceViewNotifier extends StateNotifier { void onPlaceRadiusChanged(double value) { if (state.updatedPlace == null) return; final updatePlace = state.updatedPlace?.copyWith(radius: value); - state = state.copyWith(updatedPlace: updatePlace); + state = state.copyWith(updatedPlace: updatePlace,radius: value); enableSaveBtn(); } @@ -200,6 +200,7 @@ class EditPlaceState with _$EditPlaceState { ApiPlaceMemberSetting? updatedSetting, @Default([]) List membersInfo, String? address, + double? radius, Object? error, DateTime? popToBack, DateTime? showDeleteDialog, diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view_model.freezed.dart b/app/lib/ui/flow/geofence/edit/edit_place_view_model.freezed.dart index 1a427fb4..305aa87d 100644 --- a/app/lib/ui/flow/geofence/edit/edit_place_view_model.freezed.dart +++ b/app/lib/ui/flow/geofence/edit/edit_place_view_model.freezed.dart @@ -28,6 +28,7 @@ mixin _$EditPlaceState { throw _privateConstructorUsedError; List get membersInfo => throw _privateConstructorUsedError; String? get address => throw _privateConstructorUsedError; + double? get radius => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; DateTime? get popToBack => throw _privateConstructorUsedError; DateTime? get showDeleteDialog => throw _privateConstructorUsedError; @@ -55,6 +56,7 @@ abstract class $EditPlaceStateCopyWith<$Res> { ApiPlaceMemberSetting? updatedSetting, List membersInfo, String? address, + double? radius, Object? error, DateTime? popToBack, DateTime? showDeleteDialog}); @@ -87,6 +89,7 @@ class _$EditPlaceStateCopyWithImpl<$Res, $Val extends EditPlaceState> Object? updatedSetting = freezed, Object? membersInfo = null, Object? address = freezed, + Object? radius = freezed, Object? error = freezed, Object? popToBack = freezed, Object? showDeleteDialog = freezed, @@ -136,6 +139,10 @@ class _$EditPlaceStateCopyWithImpl<$Res, $Val extends EditPlaceState> ? _value.address : address // ignore: cast_nullable_to_non_nullable as String?, + radius: freezed == radius + ? _value.radius + : radius // ignore: cast_nullable_to_non_nullable + as double?, error: freezed == error ? _value.error : error, popToBack: freezed == popToBack ? _value.popToBack @@ -194,6 +201,7 @@ abstract class _$$EditPlaceStateImplCopyWith<$Res> ApiPlaceMemberSetting? updatedSetting, List membersInfo, String? address, + double? radius, Object? error, DateTime? popToBack, DateTime? showDeleteDialog}); @@ -226,6 +234,7 @@ class __$$EditPlaceStateImplCopyWithImpl<$Res> Object? updatedSetting = freezed, Object? membersInfo = null, Object? address = freezed, + Object? radius = freezed, Object? error = freezed, Object? popToBack = freezed, Object? showDeleteDialog = freezed, @@ -275,6 +284,10 @@ class __$$EditPlaceStateImplCopyWithImpl<$Res> ? _value.address : address // ignore: cast_nullable_to_non_nullable as String?, + radius: freezed == radius + ? _value.radius + : radius // ignore: cast_nullable_to_non_nullable + as double?, error: freezed == error ? _value.error : error, popToBack: freezed == popToBack ? _value.popToBack @@ -303,6 +316,7 @@ class _$EditPlaceStateImpl implements _EditPlaceState { this.updatedSetting, final List membersInfo = const [], this.address, + this.radius, this.error, this.popToBack, this.showDeleteDialog}) @@ -344,6 +358,8 @@ class _$EditPlaceStateImpl implements _EditPlaceState { @override final String? address; @override + final double? radius; + @override final Object? error; @override final DateTime? popToBack; @@ -352,7 +368,7 @@ class _$EditPlaceStateImpl implements _EditPlaceState { @override String toString() { - return 'EditPlaceState(loading: $loading, isAdmin: $isAdmin, enableSave: $enableSave, saving: $saving, deleting: $deleting, gettingAddress: $gettingAddress, placeId: $placeId, updatedPlace: $updatedPlace, updatedSetting: $updatedSetting, membersInfo: $membersInfo, address: $address, error: $error, popToBack: $popToBack, showDeleteDialog: $showDeleteDialog)'; + return 'EditPlaceState(loading: $loading, isAdmin: $isAdmin, enableSave: $enableSave, saving: $saving, deleting: $deleting, gettingAddress: $gettingAddress, placeId: $placeId, updatedPlace: $updatedPlace, updatedSetting: $updatedSetting, membersInfo: $membersInfo, address: $address, radius: $radius, error: $error, popToBack: $popToBack, showDeleteDialog: $showDeleteDialog)'; } @override @@ -377,6 +393,7 @@ class _$EditPlaceStateImpl implements _EditPlaceState { const DeepCollectionEquality() .equals(other._membersInfo, _membersInfo) && (identical(other.address, address) || other.address == address) && + (identical(other.radius, radius) || other.radius == radius) && const DeepCollectionEquality().equals(other.error, error) && (identical(other.popToBack, popToBack) || other.popToBack == popToBack) && @@ -398,6 +415,7 @@ class _$EditPlaceStateImpl implements _EditPlaceState { updatedSetting, const DeepCollectionEquality().hash(_membersInfo), address, + radius, const DeepCollectionEquality().hash(error), popToBack, showDeleteDialog); @@ -423,6 +441,7 @@ abstract class _EditPlaceState implements EditPlaceState { final ApiPlaceMemberSetting? updatedSetting, final List membersInfo, final String? address, + final double? radius, final Object? error, final DateTime? popToBack, final DateTime? showDeleteDialog}) = _$EditPlaceStateImpl; @@ -450,6 +469,8 @@ abstract class _EditPlaceState implements EditPlaceState { @override String? get address; @override + double? get radius; + @override Object? get error; @override DateTime? get popToBack; From 6a47e4e46d57250ce993c3c3a408e65a1c817a42 Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 28 Jun 2024 12:47:09 +0530 Subject: [PATCH 32/65] Minor --- app/lib/ui/flow/geofence/edit/edit_place_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view.dart b/app/lib/ui/flow/geofence/edit/edit_place_view.dart index f1c0e4c0..02af084a 100644 --- a/app/lib/ui/flow/geofence/edit/edit_place_view.dart +++ b/app/lib/ui/flow/geofence/edit/edit_place_view.dart @@ -378,7 +378,7 @@ class _EditPlaceViewState extends ConsumerState { return Row( children: [ Text( - context.l10n.edit_place_leaves_text, + title, style: AppTextStyle.body2 .copyWith(color: context.colorScheme.textDisabled), ), From 287d708115f251ce80f14811badf430f29290865 Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 28 Jun 2024 13:13:09 +0530 Subject: [PATCH 33/65] Minor --- app/lib/ui/flow/home/map/components/space_user_footer.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/ui/flow/home/map/components/space_user_footer.dart b/app/lib/ui/flow/home/map/components/space_user_footer.dart index 1af867a8..36f82e3e 100644 --- a/app/lib/ui/flow/home/map/components/space_user_footer.dart +++ b/app/lib/ui/flow/home/map/components/space_user_footer.dart @@ -96,7 +96,7 @@ class _SpaceUserFooterState extends State { background: context.colorScheme.surface, onTap: widget.onRelocateTap, ), - const SizedBox(height: 8), + const SizedBox(height: 16), _iconButton( context: context, icon: Assets.images.icGeofenceIcon, From 72efb47142a162c75325e307000e2c2ff6e2ba49 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 10:59:57 +0530 Subject: [PATCH 34/65] Fix get search near by places --- .../add/addnew/add_new_place_view.dart | 96 ++++++-- .../add/addnew/add_new_place_view_model.dart | 11 +- .../add_new_place_view_model.freezed.dart | 40 +++- data/.flutter-plugins-dependencies | 2 +- data/lib/api/place/api_place.dart | 16 ++ data/lib/api/place/api_place.freezed.dart | 225 ++++++++++++++++++ data/lib/api/place/api_place.g.dart | 19 ++ data/lib/service/place_service.dart | 36 ++- 8 files changed, 423 insertions(+), 22 deletions(-) diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart index baa28290..2f6fa5de 100644 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart @@ -1,8 +1,10 @@ +import 'package:data/api/place/api_place.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:style/animation/on_tap_scale.dart'; import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/indicator/progress_indicator.dart'; import 'package:style/text/app_text_dart.dart'; import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; import 'package:yourspace_flutter/ui/app_route.dart'; @@ -27,27 +29,42 @@ class _AddNewPlaceViewState extends ConsumerState { @override Widget build(BuildContext context) { notifier = ref.watch(addNewPlaceStateProvider.notifier); + final state = ref.watch(addNewPlaceStateProvider); _observeError(); return AppPage( title: context.l10n.add_new_place_title, body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _searchTextField(), - const SizedBox(height: 40), - _locateOnMapView(), - const SizedBox(height: 40), - Text( - context.l10n.add_new_place_suggestion_text, - style: AppTextStyle.caption.copyWith( - color: context.colorScheme.textDisabled, + padding: EdgeInsets.only( + left: 16, + right: 16, + bottom: context.mediaQueryPadding.bottom + 24, + ), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _searchTextField(), + const SizedBox(height: 40), + _locateOnMapView(), + const SizedBox(height: 40), + Text( + context.l10n.add_new_place_suggestion_text, + style: AppTextStyle.caption.copyWith( + color: context.colorScheme.textDisabled, + ), ), - ), - ], + const SizedBox(height: 16), + ...state.places.map((place) { + final isLast = + state.places.indexOf(place) == state.places.length - 1; + return _placesItemView(place, isLast); + }), + const SizedBox(height: 24), + state.loading ? const AppProgressIndicator() : Container(), + ], + ), ), ), ); @@ -126,6 +143,57 @@ class _AddNewPlaceViewState extends ConsumerState { ); } + Widget _placesItemView(ApiNearbyPlace place, bool isLast) { + return Column( + children: [ + Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Padding( + padding: const EdgeInsets.only(top: 2), + child: Icon( + Icons.location_on_outlined, + size: 24, + color: context.colorScheme.textPrimary, + ), + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + place.name, + maxLines: 1, + style: AppTextStyle.subtitle2.copyWith( + color: context.colorScheme.textPrimary, + ), + ), + const SizedBox(height: 4), + Text( + place.formatted_address, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textSecondary), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ) + ], + ), + ) + ]), + Visibility( + visible: !isLast, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Divider( + thickness: 1, + height: 1, + color: context.colorScheme.outline, + ), + ), + ) + ], + ); + } + void _observeError() { ref.listen(addNewPlaceStateProvider.select((state) => state.error), (previous, next) { diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart index 609cb1da..10f47b5b 100644 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:data/api/place/api_place.dart'; import 'package:data/log/logger.dart'; import 'package:data/service/place_service.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -30,7 +31,14 @@ class AddNewPlaceViewNotifier extends StateNotifier { void fidePlace(String value) async { try { state = state.copyWith(loading: true); - // todo call get places api here. + final places = await placeService.searchNearbyPlaces( + value, + '', // put user latitude coordinates here. + '', // put user longitude coordinates here. + 'AIzaSyDbaJSVGU4Jkhd_V_e9esorzh_8yykh160', + ); + + state = state.copyWith(places: places, loading: false); } catch (error, stack) { state = state.copyWith(error: error, loading: false); logger.e( @@ -46,6 +54,7 @@ class AddNewPlaceViewNotifier extends StateNotifier { class AddNewPlaceState with _$AddNewPlaceState { const factory AddNewPlaceState({ @Default(false) loading, + @Default([]) List places, Object? error, }) = _AddNewPlaceState; } diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart index 37e74690..c7002a04 100644 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.freezed.dart @@ -17,6 +17,7 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$AddNewPlaceState { dynamic get loading => throw _privateConstructorUsedError; + List get places => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -30,7 +31,7 @@ abstract class $AddNewPlaceStateCopyWith<$Res> { AddNewPlaceState value, $Res Function(AddNewPlaceState) then) = _$AddNewPlaceStateCopyWithImpl<$Res, AddNewPlaceState>; @useResult - $Res call({dynamic loading, Object? error}); + $Res call({dynamic loading, List places, Object? error}); } /// @nodoc @@ -47,6 +48,7 @@ class _$AddNewPlaceStateCopyWithImpl<$Res, $Val extends AddNewPlaceState> @override $Res call({ Object? loading = freezed, + Object? places = null, Object? error = freezed, }) { return _then(_value.copyWith( @@ -54,6 +56,10 @@ class _$AddNewPlaceStateCopyWithImpl<$Res, $Val extends AddNewPlaceState> ? _value.loading : loading // ignore: cast_nullable_to_non_nullable as dynamic, + places: null == places + ? _value.places + : places // ignore: cast_nullable_to_non_nullable + as List, error: freezed == error ? _value.error : error, ) as $Val); } @@ -67,7 +73,7 @@ abstract class _$$AddNewPlaceStateImplCopyWith<$Res> __$$AddNewPlaceStateImplCopyWithImpl<$Res>; @override @useResult - $Res call({dynamic loading, Object? error}); + $Res call({dynamic loading, List places, Object? error}); } /// @nodoc @@ -82,10 +88,15 @@ class __$$AddNewPlaceStateImplCopyWithImpl<$Res> @override $Res call({ Object? loading = freezed, + Object? places = null, Object? error = freezed, }) { return _then(_$AddNewPlaceStateImpl( loading: freezed == loading ? _value.loading! : loading, + places: null == places + ? _value._places + : places // ignore: cast_nullable_to_non_nullable + as List, error: freezed == error ? _value.error : error, )); } @@ -94,17 +105,30 @@ class __$$AddNewPlaceStateImplCopyWithImpl<$Res> /// @nodoc class _$AddNewPlaceStateImpl implements _AddNewPlaceState { - const _$AddNewPlaceStateImpl({this.loading = false, this.error}); + const _$AddNewPlaceStateImpl( + {this.loading = false, + final List places = const [], + this.error}) + : _places = places; @override @JsonKey() final dynamic loading; + final List _places; + @override + @JsonKey() + List get places { + if (_places is EqualUnmodifiableListView) return _places; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_places); + } + @override final Object? error; @override String toString() { - return 'AddNewPlaceState(loading: $loading, error: $error)'; + return 'AddNewPlaceState(loading: $loading, places: $places, error: $error)'; } @override @@ -113,6 +137,7 @@ class _$AddNewPlaceStateImpl implements _AddNewPlaceState { (other.runtimeType == runtimeType && other is _$AddNewPlaceStateImpl && const DeepCollectionEquality().equals(other.loading, loading) && + const DeepCollectionEquality().equals(other._places, _places) && const DeepCollectionEquality().equals(other.error, error)); } @@ -120,6 +145,7 @@ class _$AddNewPlaceStateImpl implements _AddNewPlaceState { int get hashCode => Object.hash( runtimeType, const DeepCollectionEquality().hash(loading), + const DeepCollectionEquality().hash(_places), const DeepCollectionEquality().hash(error)); @JsonKey(ignore: true) @@ -132,11 +158,15 @@ class _$AddNewPlaceStateImpl implements _AddNewPlaceState { abstract class _AddNewPlaceState implements AddNewPlaceState { const factory _AddNewPlaceState( - {final dynamic loading, final Object? error}) = _$AddNewPlaceStateImpl; + {final dynamic loading, + final List places, + final Object? error}) = _$AddNewPlaceStateImpl; @override dynamic get loading; @override + List get places; + @override Object? get error; @override @JsonKey(ignore: true) diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index 7f9d07e4..e9e7849c 100644 --- a/data/.flutter-plugins-dependencies +++ b/data/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_apple-9.4.5/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_android-4.6.0/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_android-12.0.7/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"geolocator_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_windows-0.2.3/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_windows-0.2.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"geolocator_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_web-4.0.0/","dependencies":[]},{"name":"google_sign_in_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/","dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"permission_handler_html","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_html-0.1.1/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"geolocator","dependencies":["geolocator_android","geolocator_apple","geolocator_web","geolocator_windows"]},{"name":"geolocator_android","dependencies":[]},{"name":"geolocator_apple","dependencies":[]},{"name":"geolocator_web","dependencies":[]},{"name":"geolocator_windows","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_html","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_html","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-06-19 10:31:08.546107","version":"3.22.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_apple-9.4.5/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_android-4.6.0/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_android-12.0.7/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"geolocator_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_windows-0.2.3/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_windows-0.2.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"geolocator_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_web-4.0.0/","dependencies":[]},{"name":"google_sign_in_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/","dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"permission_handler_html","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_html-0.1.1/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"geolocator","dependencies":["geolocator_android","geolocator_apple","geolocator_web","geolocator_windows"]},{"name":"geolocator_android","dependencies":[]},{"name":"geolocator_apple","dependencies":[]},{"name":"geolocator_web","dependencies":[]},{"name":"geolocator_windows","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_html","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_html","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-06-28 16:20:49.636647","version":"3.22.0"} \ No newline at end of file diff --git a/data/lib/api/place/api_place.dart b/data/lib/api/place/api_place.dart index f3458284..202f1366 100644 --- a/data/lib/api/place/api_place.dart +++ b/data/lib/api/place/api_place.dart @@ -59,3 +59,19 @@ class ApiPlaceMemberSetting with _$ApiPlaceMemberSetting { Map toFireStore(ApiPlaceMemberSetting space) => space.toJson(); } + +@freezed +class ApiNearbyPlace with _$ApiNearbyPlace { + const ApiNearbyPlace._(); + + const factory ApiNearbyPlace({ + required String id, + required String name, + required String formatted_address, + required double lat, + required double lng, + }) = _ApiNearbyPlace; + + factory ApiNearbyPlace.fromJson(Map data) => + _$ApiNearbyPlaceFromJson(data); +} diff --git a/data/lib/api/place/api_place.freezed.dart b/data/lib/api/place/api_place.freezed.dart index d3a28d3d..398e682c 100644 --- a/data/lib/api/place/api_place.freezed.dart +++ b/data/lib/api/place/api_place.freezed.dart @@ -556,3 +556,228 @@ abstract class _ApiPlaceMemberSetting extends ApiPlaceMemberSetting { _$$ApiPlaceMemberSettingImplCopyWith<_$ApiPlaceMemberSettingImpl> get copyWith => throw _privateConstructorUsedError; } + +ApiNearbyPlace _$ApiNearbyPlaceFromJson(Map json) { + return _ApiNearbyPlace.fromJson(json); +} + +/// @nodoc +mixin _$ApiNearbyPlace { + String get id => throw _privateConstructorUsedError; + String get name => throw _privateConstructorUsedError; + String get formatted_address => throw _privateConstructorUsedError; + double get lat => throw _privateConstructorUsedError; + double get lng => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ApiNearbyPlaceCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ApiNearbyPlaceCopyWith<$Res> { + factory $ApiNearbyPlaceCopyWith( + ApiNearbyPlace value, $Res Function(ApiNearbyPlace) then) = + _$ApiNearbyPlaceCopyWithImpl<$Res, ApiNearbyPlace>; + @useResult + $Res call( + {String id, + String name, + String formatted_address, + double lat, + double lng}); +} + +/// @nodoc +class _$ApiNearbyPlaceCopyWithImpl<$Res, $Val extends ApiNearbyPlace> + implements $ApiNearbyPlaceCopyWith<$Res> { + _$ApiNearbyPlaceCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? formatted_address = null, + Object? lat = null, + Object? lng = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + formatted_address: null == formatted_address + ? _value.formatted_address + : formatted_address // ignore: cast_nullable_to_non_nullable + as String, + lat: null == lat + ? _value.lat + : lat // ignore: cast_nullable_to_non_nullable + as double, + lng: null == lng + ? _value.lng + : lng // ignore: cast_nullable_to_non_nullable + as double, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ApiNearbyPlaceImplCopyWith<$Res> + implements $ApiNearbyPlaceCopyWith<$Res> { + factory _$$ApiNearbyPlaceImplCopyWith(_$ApiNearbyPlaceImpl value, + $Res Function(_$ApiNearbyPlaceImpl) then) = + __$$ApiNearbyPlaceImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String id, + String name, + String formatted_address, + double lat, + double lng}); +} + +/// @nodoc +class __$$ApiNearbyPlaceImplCopyWithImpl<$Res> + extends _$ApiNearbyPlaceCopyWithImpl<$Res, _$ApiNearbyPlaceImpl> + implements _$$ApiNearbyPlaceImplCopyWith<$Res> { + __$$ApiNearbyPlaceImplCopyWithImpl( + _$ApiNearbyPlaceImpl _value, $Res Function(_$ApiNearbyPlaceImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? formatted_address = null, + Object? lat = null, + Object? lng = null, + }) { + return _then(_$ApiNearbyPlaceImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + formatted_address: null == formatted_address + ? _value.formatted_address + : formatted_address // ignore: cast_nullable_to_non_nullable + as String, + lat: null == lat + ? _value.lat + : lat // ignore: cast_nullable_to_non_nullable + as double, + lng: null == lng + ? _value.lng + : lng // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ApiNearbyPlaceImpl extends _ApiNearbyPlace { + const _$ApiNearbyPlaceImpl( + {required this.id, + required this.name, + required this.formatted_address, + required this.lat, + required this.lng}) + : super._(); + + factory _$ApiNearbyPlaceImpl.fromJson(Map json) => + _$$ApiNearbyPlaceImplFromJson(json); + + @override + final String id; + @override + final String name; + @override + final String formatted_address; + @override + final double lat; + @override + final double lng; + + @override + String toString() { + return 'ApiNearbyPlace(id: $id, name: $name, formatted_address: $formatted_address, lat: $lat, lng: $lng)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ApiNearbyPlaceImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.name, name) || other.name == name) && + (identical(other.formatted_address, formatted_address) || + other.formatted_address == formatted_address) && + (identical(other.lat, lat) || other.lat == lat) && + (identical(other.lng, lng) || other.lng == lng)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, id, name, formatted_address, lat, lng); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ApiNearbyPlaceImplCopyWith<_$ApiNearbyPlaceImpl> get copyWith => + __$$ApiNearbyPlaceImplCopyWithImpl<_$ApiNearbyPlaceImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ApiNearbyPlaceImplToJson( + this, + ); + } +} + +abstract class _ApiNearbyPlace extends ApiNearbyPlace { + const factory _ApiNearbyPlace( + {required final String id, + required final String name, + required final String formatted_address, + required final double lat, + required final double lng}) = _$ApiNearbyPlaceImpl; + const _ApiNearbyPlace._() : super._(); + + factory _ApiNearbyPlace.fromJson(Map json) = + _$ApiNearbyPlaceImpl.fromJson; + + @override + String get id; + @override + String get name; + @override + String get formatted_address; + @override + double get lat; + @override + double get lng; + @override + @JsonKey(ignore: true) + _$$ApiNearbyPlaceImplCopyWith<_$ApiNearbyPlaceImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/data/lib/api/place/api_place.g.dart b/data/lib/api/place/api_place.g.dart index 247e37c4..e0700a85 100644 --- a/data/lib/api/place/api_place.g.dart +++ b/data/lib/api/place/api_place.g.dart @@ -67,3 +67,22 @@ Map _$$ApiPlaceMemberSettingImplToJson( 'arrival_alert_for': instance.arrival_alert_for, 'leave_alert_for': instance.leave_alert_for, }; + +_$ApiNearbyPlaceImpl _$$ApiNearbyPlaceImplFromJson(Map json) => + _$ApiNearbyPlaceImpl( + id: json['id'] as String, + name: json['name'] as String, + formatted_address: json['formatted_address'] as String, + lat: (json['lat'] as num).toDouble(), + lng: (json['lng'] as num).toDouble(), + ); + +Map _$$ApiNearbyPlaceImplToJson( + _$ApiNearbyPlaceImpl instance) => + { + 'id': instance.id, + 'name': instance.name, + 'formatted_address': instance.formatted_address, + 'lat': instance.lat, + 'lng': instance.lng, + }; diff --git a/data/lib/service/place_service.dart b/data/lib/service/place_service.dart index 1836e2e9..9d7c63c2 100644 --- a/data/lib/service/place_service.dart +++ b/data/lib/service/place_service.dart @@ -1,9 +1,15 @@ +import 'dart:convert'; + import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/place/api_place.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:http/http.dart' as http; import '../api/network/client.dart'; +const baseUrl = 'https://maps.googleapis.com/maps/api/place/textsearch/json'; +const defaultRadius = 1500; + final placeServiceProvider = Provider( (ref) => PlaceService( ref.read(firestoreProvider), @@ -44,7 +50,6 @@ class PlaceService { String createdBy, List spaceMemberIds, ) async { - final placeDoc = spacePlacesRef(spaceId).doc(); final place = ApiPlace( @@ -76,4 +81,33 @@ class PlaceService { .set(setting.toJson()); } } + + Future> searchNearbyPlaces( + String query, + String? lat, + String? lng, + String apiKey, + ) async { + final placeRadius = (lat != null && lng != null) ? defaultRadius : ''; + final String url = + '$baseUrl?query=$query&location=$lat,$lng&radius=$placeRadius&key=$apiKey'; + + final response = await http.get(Uri.parse(url)); + + if (response.statusCode == 200) { + Map data = json.decode(response.body); + List results = data['results']; + return results.map((result) { + return ApiNearbyPlace( + id: result['place_id'] ?? '', + name: result['name'] ?? '', + formatted_address: result['formatted_address'] ?? '', + lat: result['geometry']['location']['lat']?.toDouble() ?? 0.0, + lng: result['geometry']['location']['lng']?.toDouble() ?? 0.0, + ); + }).toList(); + } else { + throw Exception('Failed to load nearby places'); + } + } } From 5645562b07ceb32bf91547242d82a93bd12367d2 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 13:55:31 +0530 Subject: [PATCH 35/65] Fix live location shown --- app/lib/ui/flow/home/map/map_view.dart | 157 +++++++++++----------- data/lib/api/space/api_space_service.dart | 8 +- data/lib/service/location_service.dart | 10 +- data/lib/service/space_service.dart | 53 ++++---- 4 files changed, 117 insertions(+), 111 deletions(-) diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index 128f9c90..d096f5d2 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -35,7 +35,7 @@ class _MapScreenState extends ConsumerState { late MapViewNotifier notifier; final Completer _controller = Completer(); final _cameraPosition = - const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); + const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); final List _markers = []; final List _places = []; @@ -113,7 +113,7 @@ class _MapScreenState extends ConsumerState { Widget _permissionFooter(MapViewState state) { final locationEnabled = - state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; + state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; final (title, subTitle) = _permissionFooterContent(state); return OnTapScale( @@ -164,7 +164,7 @@ class _MapScreenState extends ConsumerState { (String, String) _permissionFooterContent(MapViewState state) { final locationEnabled = - state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; + state.hasLocationEnabled ? state.hasLocationServiceEnabled : true; String title = ''; String subTitle = ''; @@ -197,7 +197,7 @@ class _MapScreenState extends ConsumerState { final controller = await _controller.future; if (isDarkMode) { final style = - await rootBundle.loadString('assets/map/map_theme_night.json'); + await rootBundle.loadString('assets/map/map_theme_night.json'); controller.setMapStyle(style); } else { controller.setMapStyle(null); @@ -206,57 +206,57 @@ class _MapScreenState extends ConsumerState { void _observeMapCameraPosition() { ref.listen(mapViewStateProvider.select((state) => state.defaultPosition), - (previous, next) async { - if (next != null) { - final GoogleMapController controller = await _controller.future; - await controller.animateCamera(CameraUpdate.newCameraPosition(next)); - } - }); + (previous, next) async { + if (next != null) { + final GoogleMapController controller = await _controller.future; + await controller.animateCamera(CameraUpdate.newCameraPosition(next)); + } + }); } void _observeNavigation() { ref.listen( mapViewStateProvider.select((state) => state.spaceInvitationCode), - (_, next) { - if (next.isNotEmpty) { - AppRoute.inviteCode( + (_, next) { + if (next.isNotEmpty) { + AppRoute.inviteCode( code: next, spaceName: widget.space?.space.name ?? '') - .push(context); - } - }); + .push(context); + } + }); } void _observeMarkerChange() { ref.listen(mapViewStateProvider.select((state) => state.markers), - (_, next) { - if (next.isNotEmpty) { - for (final item in next) { - _buildMarker(item); - } - } - }); + (_, next) { + if (next.isNotEmpty) { + for (final item in next) { + _buildMarker(item); + } + } + }); } void _observeShowEnableLocationPrompt(BuildContext context) { ref.listen(mapViewStateProvider.select((state) => state.showLocationDialog), - (_, next) { - if (next != null) { - showDialog( - context: context, - builder: (context) { - return PermissionDialog( - title: context.l10n.enable_location_service_title, - subTitle1: context.l10n.enable_location_service_message, - onDismiss: () {}, - goToSettings: () { - openAppSettings(); - Navigator.of(context).pop(); - }, - ); + (_, next) { + if (next != null) { + showDialog( + context: context, + builder: (context) { + return PermissionDialog( + title: context.l10n.enable_location_service_title, + subTitle1: context.l10n.enable_location_service_message, + onDismiss: () {}, + goToSettings: () { + openAppSettings(); + Navigator.of(context).pop(); }, ); - } - }); + }, + ); + } + }); } void _observeMemberPlace(BuildContext context) { @@ -265,23 +265,22 @@ class _MapScreenState extends ConsumerState { _places.clear(); _markers .removeWhere((marker) => marker.markerId.value.startsWith('place')); - - if (next.isNotEmpty) { - for (final place in next) { - final latLng = LatLng(place.latitude, place.longitude); - _placeMarker(place.id, latLng); - - _places.add(Circle( - circleId: CircleId(place.id), - fillColor: context.colorScheme.primary.withOpacity(0.4), - strokeColor: context.colorScheme.primary.withOpacity(0.6), - strokeWidth: 1, - center: latLng, - radius: place.radius, - )); - } - } }); + if (next.isNotEmpty) { + for (final place in next) { + final latLng = LatLng(place.latitude, place.longitude); + _placeMarker(place.id, latLng); + + _places.add(Circle( + circleId: CircleId(place.id), + fillColor: context.colorScheme.primary.withOpacity(0.4), + strokeColor: context.colorScheme.primary.withOpacity(0.6), + strokeWidth: 1, + center: latLng, + radius: place.radius, + )); + } + } }); } @@ -312,13 +311,13 @@ class _MapScreenState extends ConsumerState { } Future _mapMarker( - bool isSelected, - String userName, - ui.Image? imageUrl, - Color markerBgColor, - Color iconBgColor, - TextStyle textStyle, - ) async { + bool isSelected, + String userName, + ui.Image? imageUrl, + Color markerBgColor, + Color iconBgColor, + TextStyle textStyle, + ) async { if (imageUrl != null) { return await _userImageMarker(userName, imageUrl, isSelected, markerBgColor, iconBgColor, textStyle); @@ -329,12 +328,12 @@ class _MapScreenState extends ConsumerState { } Future _userCharMarker( - bool isSelected, - String userName, - Color markerBgColor, - Color iconBgColor, - TextStyle textStyle, - ) async { + bool isSelected, + String userName, + Color markerBgColor, + Color iconBgColor, + TextStyle textStyle, + ) async { final pictureRecorder = ui.PictureRecorder(); final canvas = Canvas(pictureRecorder); @@ -356,7 +355,7 @@ class _MapScreenState extends ConsumerState { final img = await picture.toImage(markerSize.toInt(), markerSize.toInt()); final byteData = await img.toByteData(format: ui.ImageByteFormat.png); final bitmapDescriptor = - BitmapDescriptor.fromBytes(byteData!.buffer.asUint8List()); + BitmapDescriptor.fromBytes(byteData!.buffer.asUint8List()); return bitmapDescriptor; } @@ -382,13 +381,13 @@ class _MapScreenState extends ConsumerState { } Future _userImageMarker( - String userName, - ui.Image uiImage, - bool isSelected, - Color markerBgColor, - Color iconBgColor, - TextStyle textStyle, - ) async { + String userName, + ui.Image uiImage, + bool isSelected, + Color markerBgColor, + Color iconBgColor, + TextStyle textStyle, + ) async { // Prepare the canvas to draw the rounded rectangle and the image final recorder = ui.PictureRecorder(); final canvas = ui.Canvas( @@ -418,11 +417,11 @@ class _MapScreenState extends ConsumerState { // End recording and create an image from the canvas final picture = recorder.endRecording(); final imgData = - await picture.toImage(markerSize.toInt(), markerSize.toInt()); + await picture.toImage(markerSize.toInt(), markerSize.toInt()); final data = await imgData.toByteData(format: ui.ImageByteFormat.png); final bitmapDescriptor = - BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); + BitmapDescriptor.fromBytes(data!.buffer.asUint8List()); return bitmapDescriptor; } @@ -476,4 +475,4 @@ class _MapScreenState extends ConsumerState { }); }); } -} \ No newline at end of file +} diff --git a/data/lib/api/space/api_space_service.dart b/data/lib/api/space/api_space_service.dart index 03ccca7b..968bdcaa 100644 --- a/data/lib/api/space/api_space_service.dart +++ b/data/lib/api/space/api_space_service.dart @@ -9,10 +9,10 @@ import '../auth/api_user_service.dart'; import '../auth/auth_models.dart'; final apiSpaceServiceProvider = StateProvider((ref) => ApiSpaceService( - ref.read(firestoreProvider), - ref.read(currentUserPod), - ref.read(apiUserServiceProvider), -)); + ref.read(firestoreProvider), + ref.read(currentUserPod), + ref.read(apiUserServiceProvider), + )); class ApiSpaceService { final FirebaseFirestore _db; diff --git a/data/lib/service/location_service.dart b/data/lib/service/location_service.dart index 74956933..fb7efda0 100644 --- a/data/lib/service/location_service.dart +++ b/data/lib/service/location_service.dart @@ -27,14 +27,16 @@ class LocationService { toFirestore: (location, _) => location.toJson()); Stream?> getCurrentLocationStream(String userId) { - return Stream.fromFuture(_locationRef(userId) + return _locationRef(userId) .where("user_id", isEqualTo: userId) - .get() - .then((snapshot) { + .orderBy('created_at', descending: true) + .limit(1) + .snapshots() + .map((snapshot) { if (snapshot.docs.isNotEmpty) { return snapshot.docs.map((doc) => doc.data() as ApiLocation).toList(); } return null; - })); + }); } } diff --git a/data/lib/service/space_service.dart b/data/lib/service/space_service.dart index 66ce2e92..398890ad 100644 --- a/data/lib/service/space_service.dart +++ b/data/lib/service/space_service.dart @@ -5,6 +5,7 @@ import 'package:data/api/space/api_space_invitation_service.dart'; import 'package:data/api/space/api_space_service.dart'; import 'package:data/api/space/space_models.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:rxdart/rxdart.dart'; import '../api/auth/auth_models.dart'; import '../storage/app_preferences.dart'; @@ -212,31 +213,35 @@ class SpaceService { } Stream> getMemberWithLocation(String spaceId) { - return Stream.fromFuture(Future(() async { - List userInfo = []; - final members = await spaceService.getMembersBySpaceId(spaceId); - - if (members.isEmpty) return []; - - for (final member in members) { - final userStream = userService.getUserStream(member.user_id); - final sessionStream = userService.getUserSessionStream(member.user_id); - final user = await userStream.first; - final locationStream = - locationService.getCurrentLocationStream(user!.id); - - final session = await sessionStream.first; - final location = await locationStream.first; - - userInfo.add(ApiUserInfo( - user: user, - location: location?.firstOrNull, - isLocationEnabled: member.location_enabled, - session: session, - )); + if (spaceId.isEmpty) { + return Stream.value([]); + } + + return Stream.fromFuture(spaceService.getMembersBySpaceId(spaceId)) + .asyncExpand((members) { + if (members.isEmpty) { + return Stream.value([]); } - return userInfo; - })); + List> userInfoStreams = members.map((member) { + return CombineLatestStream.combine4( + userService.getUserStream(member.user_id), + locationService.getCurrentLocationStream(member.user_id), + Stream.value(member.location_enabled), + userService.getUserSessionStream(member.user_id), + (user, location, isLocationEnabled, session) { + return ApiUserInfo( + user: user!, + location: location?.firstOrNull, + isLocationEnabled: isLocationEnabled, + session: session, + ); + }, + ); + }).toList(); + + return CombineLatestStream.list(userInfoStreams) + .map((userInfoList) => userInfoList.toList()); + }); } } From fa524b94a1f469b61c5d75b8ed0084caba3b7397 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 14:49:12 +0530 Subject: [PATCH 36/65] Fix search place --- .../add/addnew/add_new_place_view.dart | 67 ++++++++++--------- .../add/addnew/add_new_place_view_model.dart | 1 - data/.gitignore | 2 + data/lib/config.dart | 4 ++ data/lib/service/place_service.dart | 5 +- 5 files changed, 44 insertions(+), 35 deletions(-) create mode 100644 data/lib/config.dart diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart index 2f6fa5de..d4036af5 100644 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart @@ -146,39 +146,44 @@ class _AddNewPlaceViewState extends ConsumerState { Widget _placesItemView(ApiNearbyPlace place, bool isLast) { return Column( children: [ - Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: const EdgeInsets.only(top: 2), - child: Icon( - Icons.location_on_outlined, - size: 24, - color: context.colorScheme.textPrimary, - ), - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - place.name, - maxLines: 1, - style: AppTextStyle.subtitle2.copyWith( - color: context.colorScheme.textPrimary, - ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Padding( + padding: const EdgeInsets.only(top: 2), + child: SvgPicture.asset( + Assets.images.icLocation, + colorFilter: ColorFilter.mode( + context.colorScheme.textPrimary, + BlendMode.srcATop, ), - const SizedBox(height: 4), - Text( - place.formatted_address, - style: AppTextStyle.caption - .copyWith(color: context.colorScheme.textSecondary), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ) - ], + ), ), - ) - ]), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + place.name, + maxLines: 1, + style: AppTextStyle.subtitle2.copyWith( + color: context.colorScheme.textPrimary, + ), + ), + const SizedBox(height: 4), + Text( + place.formatted_address, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textSecondary), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ) + ], + ), + ) + ]), + ), Visibility( visible: !isLast, child: Padding( diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart index 10f47b5b..3521ba33 100644 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view_model.dart @@ -35,7 +35,6 @@ class AddNewPlaceViewNotifier extends StateNotifier { value, '', // put user latitude coordinates here. '', // put user longitude coordinates here. - 'AIzaSyDbaJSVGU4Jkhd_V_e9esorzh_8yykh160', ); state = state.copyWith(places: places, loading: false); diff --git a/data/.gitignore b/data/.gitignore index ac5aa989..49b80dca 100644 --- a/data/.gitignore +++ b/data/.gitignore @@ -22,6 +22,8 @@ migrate_working_dir/ #.vscode/ # Flutter/Dart/Pub related +**/config.dart + # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. /pubspec.lock **/doc/api/ diff --git a/data/lib/config.dart b/data/lib/config.dart new file mode 100644 index 00000000..ad0e1076 --- /dev/null +++ b/data/lib/config.dart @@ -0,0 +1,4 @@ +class AppConfig { + static const String placeBaseUrl = 'https://maps.googleapis.com/maps/api/place/textsearch/json'; + static const String mapApiKey = 'AIzaSyDbaJSVGU4Jkhd_V_e9esorzh_8yykh160'; +} diff --git a/data/lib/service/place_service.dart b/data/lib/service/place_service.dart index 9d7c63c2..6ea52ab4 100644 --- a/data/lib/service/place_service.dart +++ b/data/lib/service/place_service.dart @@ -6,8 +6,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:http/http.dart' as http; import '../api/network/client.dart'; +import '../config.dart'; -const baseUrl = 'https://maps.googleapis.com/maps/api/place/textsearch/json'; const defaultRadius = 1500; final placeServiceProvider = Provider( @@ -86,11 +86,10 @@ class PlaceService { String query, String? lat, String? lng, - String apiKey, ) async { final placeRadius = (lat != null && lng != null) ? defaultRadius : ''; final String url = - '$baseUrl?query=$query&location=$lat,$lng&radius=$placeRadius&key=$apiKey'; + '${AppConfig.placeBaseUrl}?query=$query&location=$lat,$lng&radius=$placeRadius&key=${AppConfig.mapApiKey}'; final response = await http.get(Uri.parse(url)); From 9a6928e7e43724688aff2e8591bf4b2ec8c16f52 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 15:16:02 +0530 Subject: [PATCH 37/65] Minor --- data/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/.gitignore b/data/.gitignore index 49b80dca..9da991b9 100644 --- a/data/.gitignore +++ b/data/.gitignore @@ -22,7 +22,7 @@ migrate_working_dir/ #.vscode/ # Flutter/Dart/Pub related -**/config.dart +lib/config.dart # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. /pubspec.lock From 0372657f80d71b425a41c3819e01010a1dc7b34b Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 15:28:31 +0530 Subject: [PATCH 38/65] Minor --- data/.gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data/.gitignore b/data/.gitignore index 9da991b9..80421cdf 100644 --- a/data/.gitignore +++ b/data/.gitignore @@ -22,10 +22,11 @@ migrate_working_dir/ #.vscode/ # Flutter/Dart/Pub related -lib/config.dart - # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. /pubspec.lock **/doc/api/ .dart_tool/ build/ + +# Credentials +lib/config.dart \ No newline at end of file From 199a08f05bb9d1416dca34c811b9833044b86401 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 16:10:33 +0530 Subject: [PATCH 39/65] Remove config --- data/.gitignore | 2 +- data/lib/config.dart | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) delete mode 100644 data/lib/config.dart diff --git a/data/.gitignore b/data/.gitignore index 80421cdf..fec43657 100644 --- a/data/.gitignore +++ b/data/.gitignore @@ -29,4 +29,4 @@ migrate_working_dir/ build/ # Credentials -lib/config.dart \ No newline at end of file +/lib/config.dart \ No newline at end of file diff --git a/data/lib/config.dart b/data/lib/config.dart deleted file mode 100644 index ad0e1076..00000000 --- a/data/lib/config.dart +++ /dev/null @@ -1,4 +0,0 @@ -class AppConfig { - static const String placeBaseUrl = 'https://maps.googleapis.com/maps/api/place/textsearch/json'; - static const String mapApiKey = 'AIzaSyDbaJSVGU4Jkhd_V_e9esorzh_8yykh160'; -} From 26e17a97a6bd427e6c5b8db9cc94c47bf745a674 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 17:13:58 +0530 Subject: [PATCH 40/65] Add secrets variable --- .github/workflows/android_build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index db9766cc..ab91eb9f 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -32,6 +32,7 @@ jobs: - name: Retrieve the secret and decode it to file env: + CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }} GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }} @@ -39,6 +40,8 @@ jobs: cd app echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json + cd data + echo $CONFIG_DART_BASE64 | base64 -di > data/lib/config.dart - name: Install Dependencies From 35094c3b5d1fd0401b743947297928d1abffe1c7 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 17:18:33 +0530 Subject: [PATCH 41/65] Temp --- .github/workflows/android_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index ab91eb9f..d434f25d 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -41,7 +41,7 @@ jobs: echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json cd data - echo $CONFIG_DART_BASE64 | base64 -di > data/lib/config.dart + echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart - name: Install Dependencies From fdad90536a3cbccf2c14a38cc23fccbb4f64400c Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 17:22:05 +0530 Subject: [PATCH 42/65] Temp --- .github/workflows/android_build.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index d434f25d..43186e64 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -37,11 +37,10 @@ jobs: GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }} run: | + echo $CONFIG_DART_BASE64 | base64 -di > data/lib/config.dart cd app echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json - cd data - echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart - name: Install Dependencies From 0b74d02235b212350566943f5f24eec8a09e38dd Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 17:24:10 +0530 Subject: [PATCH 43/65] Temp --- .github/workflows/android_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index 43186e64..e6e538ae 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -37,7 +37,7 @@ jobs: GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }} run: | - echo $CONFIG_DART_BASE64 | base64 -di > data/lib/config.dart + echo $CONFIG_DART_BASE64 | base64 -di > data/config.dart cd app echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json From 30a7ca1f0384b3ed858e08be90f1b1c419c00da1 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 17:52:23 +0530 Subject: [PATCH 44/65] Temp --- .github/workflows/android_build.yml | 8 +++++--- data/.flutter-plugins-dependencies | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index e6e538ae..c8219d30 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -32,15 +32,17 @@ jobs: - name: Retrieve the secret and decode it to file env: - CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }} - GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }} + GOOGLE_SERVICES_JSON_BASE64: ${.GOOGLE_SERVICES_JSON_BASE64 }} + CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} run: | - echo $CONFIG_DART_BASE64 | base64 -di > data/config.dart cd app echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json + cd .. + cd data + echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart - name: Install Dependencies diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index e9e7849c..5a0841f5 100644 --- a/data/.flutter-plugins-dependencies +++ b/data/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_apple-9.4.5/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_android-4.6.0/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_android-12.0.7/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"geolocator_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_windows-0.2.3/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_windows-0.2.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"geolocator_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_web-4.0.0/","dependencies":[]},{"name":"google_sign_in_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/","dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"permission_handler_html","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_html-0.1.1/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"geolocator","dependencies":["geolocator_android","geolocator_apple","geolocator_web","geolocator_windows"]},{"name":"geolocator_android","dependencies":[]},{"name":"geolocator_apple","dependencies":[]},{"name":"geolocator_web","dependencies":[]},{"name":"geolocator_windows","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_html","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_html","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-06-28 16:20:49.636647","version":"3.22.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_apple-9.4.5/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_android-4.6.0/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_android-12.0.7/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"geolocator_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_windows-0.2.3/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_windows-0.2.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"geolocator_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_web-4.0.0/","dependencies":[]},{"name":"google_sign_in_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/","dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"permission_handler_html","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_html-0.1.1/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"geolocator","dependencies":["geolocator_android","geolocator_apple","geolocator_web","geolocator_windows"]},{"name":"geolocator_android","dependencies":[]},{"name":"geolocator_apple","dependencies":[]},{"name":"geolocator_web","dependencies":[]},{"name":"geolocator_windows","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_html","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_html","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-07-01 17:39:46.744147","version":"3.22.2"} \ No newline at end of file From 1cbebee97c831cba25432b32c7ac4b2596f29a49 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 18:16:15 +0530 Subject: [PATCH 45/65] Temp --- .github/install_secret_script.sh | 6 +++++- .github/workflows/analyze.yml | 4 ++++ .github/workflows/android_build.yml | 5 +++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/install_secret_script.sh b/.github/install_secret_script.sh index 83078208..6aec2dee 100644 --- a/.github/install_secret_script.sh +++ b/.github/install_secret_script.sh @@ -1,6 +1,10 @@ env: FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }} GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }} + CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart -echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json \ No newline at end of file +echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json +cd ../data +echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart +cd ../app \ No newline at end of file diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 1134ce64..3f092f58 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -19,9 +19,13 @@ jobs: - name: Retrieve the secret and decode it to file env: FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }} + CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} run: | cd app echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart + cd ../data + echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart + cd .. - name: Install dependencies run: | diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index c8219d30..bb6abab1 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -40,9 +40,10 @@ jobs: cd app echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json - cd .. - cd data + + cd ../data echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart + cd .. - name: Install Dependencies From 59aaeae86efc28f5cece6f07ec39cb9237eaebbe Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 19:19:50 +0530 Subject: [PATCH 46/65] Minor --- .github/install_secret_script.sh | 8 ++++---- .github/workflows/android_build.yml | 12 +++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/install_secret_script.sh b/.github/install_secret_script.sh index 6aec2dee..71b260b0 100644 --- a/.github/install_secret_script.sh +++ b/.github/install_secret_script.sh @@ -1,10 +1,10 @@ env: + CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }} GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }} - CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} -echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart -echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json cd ../data echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart -cd ../app \ No newline at end of file +cd ../app +echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart +echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index bb6abab1..d7cb2fce 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -32,19 +32,17 @@ jobs: - name: Retrieve the secret and decode it to file env: + CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }} GOOGLE_SERVICES_JSON_BASE64: ${.GOOGLE_SERVICES_JSON_BASE64 }} - CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} + run: | - cd app - echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart - echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json - cd ../data echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart - cd .. - + cd ../app + echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart + echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json - name: Install Dependencies run: | From da1c5f5eeb142fdb4650baef512dc6d77114ccc0 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 19:23:22 +0530 Subject: [PATCH 47/65] Minor --- .github/install_secret_script.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/install_secret_script.sh b/.github/install_secret_script.sh index 71b260b0..6aec2dee 100644 --- a/.github/install_secret_script.sh +++ b/.github/install_secret_script.sh @@ -1,10 +1,10 @@ env: - CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }} GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }} + CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} -cd ../data -echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart -cd ../app echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json +cd ../data +echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart +cd ../app \ No newline at end of file From 71eaf5e7285e592868a1efc8ff47f21033d6b11d Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 19:25:56 +0530 Subject: [PATCH 48/65] Minor --- .github/workflows/android_build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index d7cb2fce..69af6ae9 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -32,17 +32,17 @@ jobs: - name: Retrieve the secret and decode it to file env: - CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }} GOOGLE_SERVICES_JSON_BASE64: ${.GOOGLE_SERVICES_JSON_BASE64 }} + CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} run: | + echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart + echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json cd ../data echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart cd ../app - echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart - echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json - name: Install Dependencies run: | From 85796bc64b8829b41a5bb0bf89042bac58083f8a Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 20:29:47 +0530 Subject: [PATCH 49/65] Minor --- .github/workflows/android_build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index 69af6ae9..bb6abab1 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -36,13 +36,15 @@ jobs: GOOGLE_SERVICES_JSON_BASE64: ${.GOOGLE_SERVICES_JSON_BASE64 }} CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} - run: | + cd app echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.json + cd ../data echo $CONFIG_DART_BASE64 | base64 -di > lib/config.dart - cd ../app + cd .. + - name: Install Dependencies run: | From 09a7c230fed67ce362aef5c270e904b4b26119f8 Mon Sep 17 00:00:00 2001 From: kaushik Date: Mon, 1 Jul 2024 20:39:55 +0530 Subject: [PATCH 50/65] Fix lint --- .github/workflows/android_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index bb6abab1..abeb91c8 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -33,7 +33,7 @@ jobs: - name: Retrieve the secret and decode it to file env: FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }} - GOOGLE_SERVICES_JSON_BASE64: ${.GOOGLE_SERVICES_JSON_BASE64 }} + GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }} CONFIG_DART_BASE64: ${{ secrets.CONFIG_DART_BASE64 }} run: | From a71d85bb411b7941a66c8b371c8a5f9bfc0e5f1c Mon Sep 17 00:00:00 2001 From: kaushik Date: Tue, 2 Jul 2024 11:55:32 +0530 Subject: [PATCH 51/65] Fix lintFix typo --- .../add/addnew/add_new_place_view.dart | 67 +++++++++------- .../add/locate/locate_on_map_view.dart | 6 +- .../add/placename/choose_place_name_view.dart | 56 +++++++------ .../geofence/places/places_list_view.dart | 80 +++++++++---------- .../places/places_list_view_model.dart | 2 +- 5 files changed, 111 insertions(+), 100 deletions(-) diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart index d4036af5..4cd17f1f 100644 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart @@ -29,42 +29,47 @@ class _AddNewPlaceViewState extends ConsumerState { @override Widget build(BuildContext context) { notifier = ref.watch(addNewPlaceStateProvider.notifier); - final state = ref.watch(addNewPlaceStateProvider); _observeError(); return AppPage( title: context.l10n.add_new_place_title, - body: Padding( - padding: EdgeInsets.only( - left: 16, - right: 16, - bottom: context.mediaQueryPadding.bottom + 24, - ), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _searchTextField(), - const SizedBox(height: 40), - _locateOnMapView(), - const SizedBox(height: 40), - Text( - context.l10n.add_new_place_suggestion_text, - style: AppTextStyle.caption.copyWith( - color: context.colorScheme.textDisabled, - ), + body: _body(), + ); + } + + Widget _body() { + final state = ref.watch(addNewPlaceStateProvider); + + return Padding( + padding: EdgeInsets.only( + left: 16, + right: 16, + bottom: context.mediaQueryPadding.bottom + 24, + ), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _searchTextField(), + const SizedBox(height: 40), + _locateOnMapView(), + const SizedBox(height: 40), + Text( + context.l10n.add_new_place_suggestion_text, + style: AppTextStyle.caption.copyWith( + color: context.colorScheme.textDisabled, ), - const SizedBox(height: 16), - ...state.places.map((place) { - final isLast = - state.places.indexOf(place) == state.places.length - 1; - return _placesItemView(place, isLast); - }), - const SizedBox(height: 24), - state.loading ? const AppProgressIndicator() : Container(), - ], - ), + ), + const SizedBox(height: 16), + ...state.places.map((place) { + final isLast = + state.places.indexOf(place) == state.places.length - 1; + return _suggestedPlaceItemView(place, isLast); + }), + const SizedBox(height: 24), + state.loading ? const AppProgressIndicator() : Container(), + ], ), ), ); @@ -143,7 +148,7 @@ class _AddNewPlaceViewState extends ConsumerState { ); } - Widget _placesItemView(ApiNearbyPlace place, bool isLast) { + Widget _suggestedPlaceItemView(ApiNearbyPlace place, bool isLast) { return Column( children: [ Padding( diff --git a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart index e30929ab..07aa926c 100644 --- a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart +++ b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart @@ -84,7 +84,9 @@ class _LocateOnMapViewState extends ConsumerState { ), Center(child: _locateMarkerView()), Align( - alignment: Alignment.bottomRight, child: _locateIconButton(context)) + alignment: Alignment.bottomRight, + child: _currentLocationIconView(context), + ) ]), ); } @@ -110,7 +112,7 @@ class _LocateOnMapViewState extends ConsumerState { ); } - Widget _locateIconButton(BuildContext context) { + Widget _currentLocationIconView(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), child: IconPrimaryButton( diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart index def8b8aa..0e23050f 100644 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart @@ -46,34 +46,38 @@ class _ChoosePlaceNameViewState extends ConsumerState { @override Widget build(BuildContext context) { - final state = ref.watch(choosePlaceViewStateProvider); - _observeError(); _observePopToPlacesListScreen(); return AppPage( title: context.l10n.choose_place_screen_title, - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _searchTextField(), - const SizedBox(height: 40), - Text( - context.l10n.choose_place_suggestion_text, - style: AppTextStyle.caption - .copyWith(color: context.colorScheme.textDisabled), - ), - const SizedBox(height: 16), - _suggestionsView(state.suggestions), - const Spacer(), - Align( - alignment: Alignment.center, - child: _addPlaceButtonView(state), - ) - ], - ), + body: _body(), + ); + } + + Widget _body() { + final state = ref.watch(choosePlaceViewStateProvider); + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _searchTextField(), + const SizedBox(height: 40), + Text( + context.l10n.choose_place_suggestion_text, + style: AppTextStyle.caption + .copyWith(color: context.colorScheme.textDisabled), + ), + const SizedBox(height: 16), + _suggestionsPlaceView(state.suggestions), + const Spacer(), + Align( + alignment: Alignment.center, + child: _addPlaceButtonView(state), + ) + ], ), ); } @@ -117,7 +121,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { ); } - Widget _suggestionsView(List? suggestions) { + Widget _suggestionsPlaceView(List? suggestions) { if (suggestions == null) return Container(); return Wrap( alignment: WrapAlignment.start, @@ -179,7 +183,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { choosePlaceViewStateProvider.select((state) => state.popToPlaceList), (_, next) { AppRoute.popTo(context, AppRoute.pathPlacesList); - _showPlaceAddedPrompt( + _showPlaceAddedDialog( context, widget.location.latitude, widget.location.longitude, @@ -188,7 +192,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { }); } - void _showPlaceAddedPrompt( + void _showPlaceAddedDialog( BuildContext context, double lat, double lng, diff --git a/app/lib/ui/flow/geofence/places/places_list_view.dart b/app/lib/ui/flow/geofence/places/places_list_view.dart index 2fafec41..b8eefe06 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view.dart @@ -60,7 +60,7 @@ class _PlacesViewState extends ConsumerState { itemCount: placeLength + state.suggestions.length, itemBuilder: (_, index) { if (index < state.places.length) { - return _placesListItem(state, state.places[index]); + return _memberPlaceItem(state, state.places[index]); } if (index == state.places.length && state.places.isNotEmpty) { @@ -90,45 +90,7 @@ class _PlacesViewState extends ConsumerState { ); } - Widget _addPlaceButton() { - return OnTapScale( - onTap: () { - AppRoute.addNewPlace(widget.spaceId).push(context); - }, - child: Container( - margin: EdgeInsets.only( - right: 16, - bottom: context.mediaQueryPadding.bottom + 16, - ), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(30), - color: context.colorScheme.primary, - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - SvgPicture.asset( - Assets.images.icPlusIcon, - colorFilter: ColorFilter.mode( - context.colorScheme.onPrimary, - BlendMode.srcATop, - ), - ), - const SizedBox(width: 8), - Text( - context.l10n.places_list_add_place_btn_text, - style: AppTextStyle.button.copyWith( - color: context.colorScheme.onPrimary, - ), - ) - ], - ), - ), - ); - } - - Widget _placesListItem(PlacesListState state, ApiPlace item) { + Widget _memberPlaceItem(PlacesListState state, ApiPlace item) { final icon = _getPlacesIcon(item.name); final isDeleting = state.deletingPlaces && state.placesToDelete?.id == item.id; @@ -205,6 +167,44 @@ class _PlacesViewState extends ConsumerState { ); } + Widget _addPlaceButton() { + return OnTapScale( + onTap: () { + AppRoute.addNewPlace(widget.spaceId).push(context); + }, + child: Container( + margin: EdgeInsets.only( + right: 16, + bottom: context.mediaQueryPadding.bottom + 16, + ), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: context.colorScheme.primary, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SvgPicture.asset( + Assets.images.icPlusIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.onPrimary, + BlendMode.srcATop, + ), + ), + const SizedBox(width: 8), + Text( + context.l10n.places_list_add_place_btn_text, + style: AppTextStyle.button.copyWith( + color: context.colorScheme.onPrimary, + ), + ) + ], + ), + ), + ); + } + String _getPlacesIcon(String name) { if (name == 'Home') { return Assets.images.icPlacesHomeIcon; diff --git a/app/lib/ui/flow/geofence/places/places_list_view_model.dart b/app/lib/ui/flow/geofence/places/places_list_view_model.dart index b91978d5..9eefcfce 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view_model.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view_model.dart @@ -75,7 +75,7 @@ class PlacesListViewNotifier extends StateNotifier { } void dismissDeletePlaceDialog() { - state = state.copyWith(deletingPlaces: false, placesToDelete: null); + state = state.copyWith(placesToDelete: null); } void deletePlace() async { From 1890f58fc6c296a31cda7cbd7d84e891cbc58238 Mon Sep 17 00:00:00 2001 From: kaushik Date: Tue, 2 Jul 2024 12:30:49 +0530 Subject: [PATCH 52/65] Fix typo --- .../flow/geofence/edit/edit_place_view.dart | 6 ++-- .../geofence/edit/edit_place_view_model.dart | 28 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view.dart b/app/lib/ui/flow/geofence/edit/edit_place_view.dart index 02af084a..9123c9b2 100644 --- a/app/lib/ui/flow/geofence/edit/edit_place_view.dart +++ b/app/lib/ui/flow/geofence/edit/edit_place_view.dart @@ -51,7 +51,7 @@ class _EditPlaceViewState extends ConsumerState { runPostFrame(() { notifier = ref.watch(editPlaceViewStateProvider.notifier); - notifier.loadDate(widget.place); + notifier.loadData(widget.place); }); } @@ -207,7 +207,7 @@ class _EditPlaceViewState extends ConsumerState { .copyWith(color: context.colorScheme.textDisabled), ), const SizedBox(height: 16), - _searchTextField(place.name, Icons.bookmark, state.isAdmin), + _placeTextField(place.name, Icons.bookmark, state.isAdmin), const SizedBox(height: 16), _placeAddressView(address), const SizedBox(height: 8), @@ -217,7 +217,7 @@ class _EditPlaceViewState extends ConsumerState { ); } - Widget _searchTextField(String placeName, IconData iconData, bool isAdmin) { + Widget _placeTextField(String placeName, IconData iconData, bool isAdmin) { return Column( children: [ TextField( diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart b/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart index f1a5966b..0e1c78a5 100644 --- a/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart +++ b/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart @@ -32,7 +32,7 @@ class EditPlaceViewNotifier extends StateNotifier { EditPlaceViewNotifier(this._currentUser, this.placeService, this.spaceService) : super(const EditPlaceState()); - void loadDate(ApiPlace place) async { + void loadData(ApiPlace place) async { if (state.loading) return; try { state = state.copyWith(loading: true); @@ -44,8 +44,10 @@ class EditPlaceViewNotifier extends StateNotifier { final membersInfo = spaceInfo?.members .where((member) => member.user.id != _currentUser.id) .toList(); + _place = place; _setting = setting; + state = state.copyWith( updatedPlace: place, membersInfo: membersInfo ?? [], @@ -85,6 +87,18 @@ class EditPlaceViewNotifier extends StateNotifier { enableSaveBtn(); } + void onPlaceRadiusChanged(double value) { + if (state.updatedPlace == null) return; + final updatePlace = state.updatedPlace?.copyWith(radius: value); + state = state.copyWith(updatedPlace: updatePlace,radius: value); + enableSaveBtn(); + } + + void onPlaceNameChanged(String value) { + final updatedPlace = state.updatedPlace?.copyWith(name: value); + state = state.copyWith(updatedPlace: updatedPlace); + } + void onToggleArrives(String userId, bool arrives) { final arrivesList = List.from(state.updatedSetting?.arrival_alert_for ?? []); @@ -101,11 +115,6 @@ class EditPlaceViewNotifier extends StateNotifier { enableSaveBtn(); } - void onPlaceNameChanged(String value) { - final updatedPlace = state.updatedPlace?.copyWith(name: value); - state = state.copyWith(updatedPlace: updatedPlace); - } - void onToggleLeaves(String userId, bool leaves) { final leaveList = List.from(state.updatedSetting?.leave_alert_for ?? []); @@ -121,13 +130,6 @@ class EditPlaceViewNotifier extends StateNotifier { } } - void onPlaceRadiusChanged(double value) { - if (state.updatedPlace == null) return; - final updatePlace = state.updatedPlace?.copyWith(radius: value); - state = state.copyWith(updatedPlace: updatePlace,radius: value); - enableSaveBtn(); - } - void enableSaveBtn() { final isChanged = state.updatedPlace != _place || (_setting != null && state.updatedSetting != _setting); From 4035f5c14832e17f6d6ea84600a513770222ddca Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 3 Jul 2024 14:16:04 +0530 Subject: [PATCH 53/65] Fix real time update --- app/android/app/src/main/AndroidManifest.xml | 5 + app/lib/ui/flow/home/map/map_view.dart | 173 +++++++++--------- app/lib/ui/flow/home/map/map_view_model.dart | 1 + .../flow/setting/profile/profile_screen.dart | 77 ++++---- app/pubspec.lock | 68 ++++++- app/pubspec.yaml | 4 +- data/lib/api/space/api_space_service.dart | 11 ++ data/lib/service/space_service.dart | 5 +- 8 files changed, 210 insertions(+), 134 deletions(-) diff --git a/app/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml index b276d897..cc2e8ddd 100644 --- a/app/android/app/src/main/AndroidManifest.xml +++ b/app/android/app/src/main/AndroidManifest.xml @@ -33,6 +33,11 @@ + + diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index d096f5d2..5be94424 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -20,7 +20,7 @@ import 'map_view_model.dart'; const defaultCameraZoom = 15.0; const defaultCameraZoomForSelectedUser = 17.0; const markerSize = 100.0; -const placeSize = 80.0; +const placeSize = 80; class MapView extends ConsumerStatefulWidget { final SpaceInfo? space; @@ -33,20 +33,21 @@ class MapView extends ConsumerStatefulWidget { class _MapScreenState extends ConsumerState { late MapViewNotifier notifier; - final Completer _controller = Completer(); + GoogleMapController? _controller; final _cameraPosition = const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); + String? _mapStyle; - final List _markers = []; - final List _places = []; + List _markers = []; + List _places = []; @override void didUpdateWidget(covariant MapView oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.space?.space.id != widget.space?.space.id) { setState(() { - _markers.clear(); - _places.clear(); + _markers = []; + _places = []; }); } } @@ -69,6 +70,7 @@ class _MapScreenState extends ConsumerState { child: GoogleMap( onMapCreated: _onMapCreated, initialCameraPosition: _cameraPosition, + style: _mapStyle, compassEnabled: false, zoomControlsEnabled: false, tiltGesturesEnabled: false, @@ -190,26 +192,26 @@ class _MapScreenState extends ConsumerState { } void _onMapCreated(GoogleMapController controller) async { - _controller.complete(controller); + _controller = controller; } void _updateMapStyle(bool isDarkMode) async { - final controller = await _controller.future; - if (isDarkMode) { - final style = - await rootBundle.loadString('assets/map/map_theme_night.json'); - controller.setMapStyle(style); - } else { - controller.setMapStyle(null); - } + final style = + await rootBundle.loadString('assets/map/map_theme_night.json'); + setState(() { + if (isDarkMode) { + _mapStyle = style; + } else { + _mapStyle = null; + } + }); } void _observeMapCameraPosition() { ref.listen(mapViewStateProvider.select((state) => state.defaultPosition), (previous, next) async { if (next != null) { - final GoogleMapController controller = await _controller.future; - await controller.animateCamera(CameraUpdate.newCameraPosition(next)); + await _controller?.animateCamera(CameraUpdate.newCameraPosition(next)); } }); } @@ -228,7 +230,10 @@ class _MapScreenState extends ConsumerState { void _observeMarkerChange() { ref.listen(mapViewStateProvider.select((state) => state.markers), - (_, next) { + (previous, next) { + if (previous?.length != next.length) { + _clearNonPlaceMarkers(); + } if (next.isNotEmpty) { for (final item in next) { _buildMarker(item); @@ -259,31 +264,6 @@ class _MapScreenState extends ConsumerState { }); } - void _observeMemberPlace(BuildContext context) { - ref.listen(mapViewStateProvider.select((state) => state.places), (_, next) { - setState(() { - _places.clear(); - _markers - .removeWhere((marker) => marker.markerId.value.startsWith('place')); - }); - if (next.isNotEmpty) { - for (final place in next) { - final latLng = LatLng(place.latitude, place.longitude); - _placeMarker(place.id, latLng); - - _places.add(Circle( - circleId: CircleId(place.id), - fillColor: context.colorScheme.primary.withOpacity(0.4), - strokeColor: context.colorScheme.primary.withOpacity(0.6), - strokeWidth: 1, - center: latLng, - radius: place.radius, - )); - } - } - }); - } - void _buildMarker(UserMarker item) async { final marker = await _mapMarker( item.isSelected, @@ -426,53 +406,80 @@ class _MapScreenState extends ConsumerState { return bitmapDescriptor; } - void _placeMarker(String placeId, LatLng latLng) async { - rootBundle - .load('assets/images/ic_place_marker_icon.png') - .then((ByteData data) { - ui - .instantiateImageCodec(data.buffer.asUint8List()) - .then((ui.Codec codec) { - codec.getNextFrame().then((ui.FrameInfo fi) { - _drawPlaceMarker(fi, placeId, latLng); - }); - }); + void _observeMemberPlace(BuildContext context) { + ref.listen(mapViewStateProvider.select((state) => state.places), + (previous, next) { + if (previous?.length != next.length) { + _clearPlacesAndPlaceMarkers(); + } + + if (next.isNotEmpty) { + for (final place in next) { + final latLng = LatLng(place.latitude, place.longitude); + + _generatePlaceMarker(place.id, latLng); + setState(() { + _places.add(Circle( + circleId: CircleId(place.id), + fillColor: context.colorScheme.primary.withOpacity(0.4), + strokeColor: context.colorScheme.primary.withOpacity(0.6), + strokeWidth: 1, + center: latLng, + radius: place.radius, + )); + }); + } + } }); } - void _drawPlaceMarker(ui.FrameInfo frameInfo, String placeId, LatLng latLng) { - final pictureRecorder = ui.PictureRecorder(); - final canvas = Canvas(pictureRecorder); - final paint = Paint()..color = Colors.white; + void _generatePlaceMarker(String id, LatLng latLng) async { + final icon = + await _createCustomIcon('assets/images/ic_place_marker_icon.png'); + + setState(() { + _markers.add( + Marker( + markerId: MarkerId("place_$id"), + position: latLng, + anchor: const Offset(0.5, 0.5), + zIndex: 1, + icon: icon, + ), + ); + }); + } - canvas.drawCircle( - const Offset(placeSize / 2, placeSize / 2), placeSize / 2, paint); + Future _createCustomIcon(String assetPath) async { + final data = await rootBundle.load(assetPath); + final bytes = data.buffer.asUint8List(); - paintImage( - canvas: canvas, - image: frameInfo.image, - rect: const Rect.fromLTWH(0, 0, placeSize, placeSize), - fit: BoxFit.contain, + final codec = await ui.instantiateImageCodec( + bytes, + targetWidth: placeSize, + targetHeight: placeSize, ); + final frameInfo = await codec.getNextFrame(); - pictureRecorder - .endRecording() - .toImage(placeSize.toInt(), placeSize.toInt()) - .then((ui.Image markerAsImage) { - markerAsImage - .toByteData(format: ui.ImageByteFormat.png) - .then((ByteData? byteData) { - if (byteData != null) { - final Uint8List uint8List = byteData.buffer.asUint8List(); - - _markers.add(Marker( - markerId: MarkerId('place-$placeId'), - position: latLng, - anchor: const Offset(0.5, 0.5), - icon: BitmapDescriptor.fromBytes(uint8List), - )); - } - }); + final byteData = + await frameInfo.image.toByteData(format: ui.ImageByteFormat.png); + final resizedBytes = byteData!.buffer.asUint8List(); + + return BitmapDescriptor.fromBytes(resizedBytes); + } + + void _clearPlacesAndPlaceMarkers() { + setState(() { + _places = []; + _markers + .removeWhere((marker) => marker.markerId.value.startsWith('place')); + }); + } + + void _clearNonPlaceMarkers() { + setState(() { + _markers + .removeWhere((marker) => !marker.markerId.value.startsWith('place')); }); } } diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index 19ced228..563ce0e5 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -65,6 +65,7 @@ class MapViewNotifier extends StateNotifier { if (state.loading) return; try { state = state.copyWith(loading: true, selectedUser: null); + spaceService.getMemberWithLocation(spaceId).listen((userInfo) { state = state.copyWith(userInfo: userInfo, loading: false); userMapPositions(userInfo); diff --git a/app/lib/ui/flow/setting/profile/profile_screen.dart b/app/lib/ui/flow/setting/profile/profile_screen.dart index dc697c6f..3fe381b8 100644 --- a/app/lib/ui/flow/setting/profile/profile_screen.dart +++ b/app/lib/ui/flow/setting/profile/profile_screen.dart @@ -4,12 +4,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:go_router/go_router.dart'; -import 'package:image_picker/image_picker.dart'; import 'package:image_cropper/image_cropper.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:style/animation/on_tap_scale.dart'; +import 'package:style/button/action_button.dart'; import 'package:style/button/bottom_sticky_overlay.dart'; import 'package:style/button/primary_button.dart'; -import 'package:style/button/action_button.dart'; import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/indicator/progress_indicator.dart'; import 'package:style/text/app_text_dart.dart'; @@ -51,12 +51,12 @@ class _ProfileScreenState extends ConsumerState { icon: state.saving ? const AppProgressIndicator(size: AppProgressIndicatorSize.small) : Icon( - Icons.check, - size: 24, - color: state.allowSave - ? context.colorScheme.primary - : context.colorScheme.textDisabled, - ), + Icons.check, + size: 24, + color: state.allowSave + ? context.colorScheme.primary + : context.colorScheme.textDisabled, + ), onPressed: () { if (state.allowSave) { notifier.save(); @@ -78,15 +78,19 @@ class _ProfileScreenState extends ConsumerState { children: [ _profileImage(context, ref, state.profileUrl), const SizedBox(height: 40), - _textFields(context, context.l10n.edit_profile_first_name_title, state.firstName), + _textFields(context, context.l10n.edit_profile_first_name_title, + state.firstName), const SizedBox(height: 16), - _textFields(context, context.l10n.edit_profile_last_name_title, state.lastName), + _textFields(context, context.l10n.edit_profile_last_name_title, + state.lastName), const SizedBox(height: 16), _textFields( - context, context.l10n.edit_profile_email_title, state.email, enabled: state.enableEmail), + context, context.l10n.edit_profile_email_title, state.email, + enabled: state.enableEmail), const SizedBox(height: 16), _textFields( - context, context.l10n.edit_profile_phone_title, state.phone, enabled: state.enablePhone), + context, context.l10n.edit_profile_phone_title, state.phone, + enabled: state.enablePhone), ], ), _deleteAccountButton(context), @@ -94,8 +98,8 @@ class _ProfileScreenState extends ConsumerState { ); } - Widget _profileImage(BuildContext context, WidgetRef ref, - String? profileImage) { + Widget _profileImage( + BuildContext context, WidgetRef ref, String? profileImage) { final state = ref.watch(editProfileViewStateProvider); return Center( child: OnTapScale( @@ -116,18 +120,17 @@ class _ProfileScreenState extends ConsumerState { borderRadius: BorderRadius.circular(64), ), child: (state.profileUrl.isEmpty) - ? Center(child: Text( - notifier.user?.userNameFirstLetter ?? '', - style: TextStyle( - fontSize: 44, - fontWeight: FontWeight.bold, - color: context.colorScheme.textPrimaryDark, - ) - )) + ? Center( + child: Text(notifier.user?.userNameFirstLetter ?? '', + style: TextStyle( + fontSize: 44, + fontWeight: FontWeight.bold, + color: context.colorScheme.textPrimaryDark, + ))) : CachedNetworkImage( - imageUrl: state.profileUrl, - fit: BoxFit.cover, - ), + imageUrl: state.profileUrl, + fit: BoxFit.cover, + ), ), Align( alignment: Alignment.bottomRight, @@ -227,17 +230,17 @@ class _ProfileScreenState extends ConsumerState { void _openCropImage(BuildContext context, XFile image) async { final croppedImage = await ImageCropper().cropImage( sourcePath: image.path, - aspectRatioPresets: [CropAspectRatioPreset.square], uiSettings: [ AndroidUiSettings( toolbarTitle: context.l10n.edit_profile_cropper_text, toolbarColor: context.colorScheme.primary, toolbarWidgetColor: context.colorScheme.onPrimary, - initAspectRatio: CropAspectRatioPreset.square, + aspectRatioPresets: [CropAspectRatioPreset.square], lockAspectRatio: true, ), IOSUiSettings( title: context.l10n.edit_profile_cropper_text, + aspectRatioPresets: [CropAspectRatioPreset.square], ), WebUiSettings( context: context, @@ -248,8 +251,9 @@ class _ProfileScreenState extends ConsumerState { if (croppedImage != null) notifier.uploadProfileImage(croppedImage.path); } - Widget _textFields(BuildContext context, String title, - TextEditingController controller, {bool enabled = true}) { + Widget _textFields( + BuildContext context, String title, TextEditingController controller, + {bool enabled = true}) { return AppTextField( controller: controller, label: title, @@ -266,8 +270,7 @@ class _ProfileScreenState extends ConsumerState { child: PrimaryButton( context.l10n.edit_profile_delete_account_title, expanded: false, - edgeInsets: - const EdgeInsets.symmetric(vertical: 14, horizontal: 24), + edgeInsets: const EdgeInsets.symmetric(vertical: 14, horizontal: 24), showIcon: true, foreground: context.colorScheme.alert, background: context.colorScheme.containerLow, @@ -285,9 +288,8 @@ class _ProfileScreenState extends ConsumerState { } void _observePop() { - ref.listen( - editProfileViewStateProvider.select((state) => state.saved), (previous, - next) { + ref.listen(editProfileViewStateProvider.select((state) => state.saved), + (previous, next) { if (next) { context.pop(); } @@ -296,8 +298,8 @@ class _ProfileScreenState extends ConsumerState { void _observeAccountDeleted() { ref.listen( - editProfileViewStateProvider.select((state) => state.accountDeleted), ( - previous, next) { + editProfileViewStateProvider.select((state) => state.accountDeleted), + (previous, next) { if (next) { AppRoute.signInMethod.push(context); } @@ -305,7 +307,8 @@ class _ProfileScreenState extends ConsumerState { } void _observeError() { - ref.listen(editProfileViewStateProvider.select((state) => state.error), (previous, next) { + ref.listen(editProfileViewStateProvider.select((state) => state.error), + (previous, next) { if (next != null) { showErrorSnackBar(context, next.toString()); } diff --git a/app/pubspec.lock b/app/pubspec.lock index b75d9f9f..ddbe9782 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -297,6 +297,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" cupertino_icons: dependency: "direct main" description: @@ -732,14 +740,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1+1" + google_maps: + dependency: transitive + description: + name: google_maps + sha256: "47eef3836b49bb030d5cb3afc60b8451408bf34cf753e571b645d6529eb4251a" + url: "https://pub.dev" + source: hosted + version: "7.1.0" google_maps_flutter: dependency: "direct main" description: name: google_maps_flutter - sha256: abefcb1e5e5c96bdd8084939dda555257af272c7972902ca46d5631092c1df68 + sha256: acf0ec482d86b2ac55ade80597ce7f797a47971f5210ebfd030f0d58130e0a94 url: "https://pub.dev" source: hosted - version: "2.2.8" + version: "2.7.0" google_maps_flutter_android: dependency: transitive description: @@ -764,6 +780,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.7.1" + google_maps_flutter_web: + dependency: transitive + description: + name: google_maps_flutter_web + sha256: f3155c12119d8a5c2732fdf39ceb5cc095bc662059a03b4ea23294ecebe1d199 + url: "https://pub.dev" + source: hosted + version: "0.5.8" google_sign_in: dependency: "direct main" description: @@ -828,6 +852,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.2.0" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" http: dependency: "direct main" description: @@ -864,26 +896,26 @@ packages: dependency: "direct main" description: name: image_cropper - sha256: db779a8b620cd509874cb0e2a8bdc8649177f8f5ca46c13273ceaffe071e3f4a + sha256: d31be025c744ac1bf52d1f49cfdd92fd421e7e45ddadaaac0b39901f67c2a7e3 url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "7.1.0" image_cropper_for_web: dependency: transitive description: name: image_cropper_for_web - sha256: ba67de40a98b3294084eed0b025b557cb594356e1171c9a830b340527dbd5e5f + sha256: "6386e64908ce5d5df404e01c750a99b633dfcea88da69b3efcd3b3811d639760" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.1.0" image_cropper_platform_interface: dependency: transitive description: name: image_cropper_platform_interface - sha256: ee160d686422272aa306125f3b6fb1c1894d9b87a5e20ed33fa008e7285da11e + sha256: "39c6539571bda7ce666e0a2f450246a5d42187406eef8f486a3d64f1d9381637" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.1.0" image_picker: dependency: "direct main" description: @@ -976,10 +1008,18 @@ packages: dependency: transitive description: name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + js_wrapping: + dependency: transitive + description: + name: js_wrapping + sha256: e385980f7c76a8c1c9a560dfb623b890975841542471eade630b2871d243851c url: "https://pub.dev" source: hosted - version: "0.7.1" + version: "0.7.4" json_annotation: dependency: "direct main" description: @@ -1300,6 +1340,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" + sanitize_html: + dependency: transitive + description: + name: sanitize_html + sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989" + url: "https://pub.dev" + source: hosted + version: "2.1.0" share_plus: dependency: "direct main" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 1abc8ab7..630650a5 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -52,7 +52,7 @@ dependencies: visibility_detector: ^0.4.0+2 cached_network_image: ^3.3.1 image_picker: ^1.1.1 - image_cropper: ^6.0.0 + image_cropper: ^7.1.0 fluttertoast: ^8.2.6 http: ^1.2.1 image: ^3.0.1 @@ -60,7 +60,7 @@ dependencies: permission_handler: ^11.3.1 # map - google_maps_flutter: ^2.2.8 + google_maps_flutter: ^2.3.1 geocoding: ^3.0.0 geolocator: ^12.0.0 diff --git a/data/lib/api/space/api_space_service.dart b/data/lib/api/space/api_space_service.dart index 968bdcaa..ab162911 100644 --- a/data/lib/api/space/api_space_service.dart +++ b/data/lib/api/space/api_space_service.dart @@ -83,6 +83,17 @@ class ApiSpaceService { }).toList(); } + Stream> getStreamSpaceMemberBySpaceId(String spaceId) { + return FirebaseFirestore.instance + .collection('spaces') + .doc(spaceId) + .collection('space_members') + .snapshots() + .map((querySnapshot) => querySnapshot.docs + .map((doc) => ApiSpaceMember.fromJson(doc.data())) + .toList()); + } + Future> getSpaceMemberByUserId(String userId) async { final querySnapshot = await _spaceRef.firestore .collectionGroup('space_members') diff --git a/data/lib/service/space_service.dart b/data/lib/service/space_service.dart index 398890ad..72eb2cb0 100644 --- a/data/lib/service/space_service.dart +++ b/data/lib/service/space_service.dart @@ -217,8 +217,9 @@ class SpaceService { return Stream.value([]); } - return Stream.fromFuture(spaceService.getMembersBySpaceId(spaceId)) - .asyncExpand((members) { + return spaceService + .getStreamSpaceMemberBySpaceId(spaceId) + .switchMap((members) { if (members.isEmpty) { return Stream.value([]); } From 05a69ad6694a8d4c35343babf97a29566082efd7 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 3 Jul 2024 14:29:50 +0530 Subject: [PATCH 54/65] Minor --- app/lib/ui/flow/geofence/places/places_list_view_model.dart | 3 +-- app/lib/ui/flow/home/map/map_view.dart | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/lib/ui/flow/geofence/places/places_list_view_model.dart b/app/lib/ui/flow/geofence/places/places_list_view_model.dart index d8cd121c..e4e15dce 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view_model.dart +++ b/app/lib/ui/flow/geofence/places/places_list_view_model.dart @@ -56,8 +56,7 @@ class PlacesListViewNotifier extends StateNotifier { for (final place in places) { final placeName = place.name.toLowerCase(); - if (state.currentUser?.id == place.created_by && - suggestionName == placeName) { + if (suggestionName == placeName) { return false; } } diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index 5be94424..e0abcc48 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -104,7 +104,11 @@ class _MapScreenState extends ConsumerState { notifier.showMemberDetail(member); }, onRelocateTap: () {}, - onPlacesTap: () {}, + onPlacesTap: () { + if (widget.space != null) { + AppRoute.placesList(widget.space!.space.id).push(context); + } + }, onDismiss: () => notifier.onDismissMemberDetail(), onTapTimeline: () {}, ), From d55e55ae72197b020dfddcdc851a9fed78ffddf0 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 3 Jul 2024 15:00:58 +0530 Subject: [PATCH 55/65] Fix config --- .../flow/home/map/components/space_user_footer.dart | 2 +- data/.flutter-plugins-dependencies | 2 +- data/lib/api/auth/auth_models.dart | 5 ----- style/lib/button/icon_primary_button.dart | 11 +++-------- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/app/lib/ui/flow/home/map/components/space_user_footer.dart b/app/lib/ui/flow/home/map/components/space_user_footer.dart index 1af867a8..5b2d8d81 100644 --- a/app/lib/ui/flow/home/map/components/space_user_footer.dart +++ b/app/lib/ui/flow/home/map/components/space_user_footer.dart @@ -123,7 +123,7 @@ class _SpaceUserFooterState extends State { return Visibility( visible: visibility, child: IconPrimaryButton( - backgroundColor: background, + bgColor: background, onTap: () => onTap(), icon: SvgPicture.asset( icon, diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index 281790ef..32924483 100644 --- a/data/.flutter-plugins-dependencies +++ b/data/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.23/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.2/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/ishita/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/Users/ishita/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"google_sign_in_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+3/","dependencies":[]},{"name":"package_info_plus","path":"/Users/ishita/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/ishita/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-06-11 17:20:21.066671","version":"3.22.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_apple-9.4.5/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_android-4.6.0/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.24/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_android-12.0.7/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"cloud_functions","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions-4.7.6/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","native_build":true,"dependencies":[]},{"name":"geolocator_apple","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_apple-2.3.7/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.6/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"cloud_firestore","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore-4.17.5/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth-4.20.0/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[]},{"name":"firebase_storage","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage-11.7.7/","native_build":true,"dependencies":["firebase_core"]},{"name":"geolocator_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_windows-0.2.3/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_windows-0.2.1/","native_build":true,"dependencies":[]},{"name":"shared_preferences_windows","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"cloud_firestore_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_firestore_web-3.12.5/","dependencies":["firebase_core_web"]},{"name":"cloud_functions_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/cloud_functions_web-4.9.6/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2/","dependencies":[]},{"name":"firebase_auth_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_auth_web-5.12.0/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.1/","dependencies":[]},{"name":"firebase_storage_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/firebase_storage_web-3.9.7/","dependencies":["firebase_core_web"]},{"name":"flutter_timezone","path":"/home/kaushik/.pub-cache/hosted/pub.dev/flutter_timezone-1.0.8/","dependencies":[]},{"name":"geolocator_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/geolocator_web-4.0.0/","dependencies":[]},{"name":"google_sign_in_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4/","dependencies":[]},{"name":"package_info_plus","path":"/home/kaushik/.pub-cache/hosted/pub.dev/package_info_plus-8.0.0/","dependencies":[]},{"name":"permission_handler_html","path":"/home/kaushik/.pub-cache/hosted/pub.dev/permission_handler_html-0.1.1/","dependencies":[]},{"name":"shared_preferences_web","path":"/home/kaushik/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"cloud_functions","dependencies":["cloud_functions_web","firebase_core"]},{"name":"cloud_functions_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core","firebase_storage_web"]},{"name":"firebase_storage_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_timezone","dependencies":[]},{"name":"geolocator","dependencies":["geolocator_android","geolocator_apple","geolocator_web","geolocator_windows"]},{"name":"geolocator_android","dependencies":[]},{"name":"geolocator_apple","dependencies":[]},{"name":"geolocator_web","dependencies":[]},{"name":"geolocator_windows","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_html","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_html","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2024-07-03 14:46:27.136362","version":"3.22.2"} \ No newline at end of file diff --git a/data/lib/api/auth/auth_models.dart b/data/lib/api/auth/auth_models.dart index 9e3f0d73..08b7a8d3 100644 --- a/data/lib/api/auth/auth_models.dart +++ b/data/lib/api/auth/auth_models.dart @@ -51,11 +51,6 @@ class ApiUser with _$ApiUser { String get firstChar { return first_name!.isNotEmpty ? first_name![0].toUpperCase() : ''; } - - String get firstChar { - final trimmedName = fullName.trim(); - return trimmedName.isNotEmpty ? trimmedName[0] : '?'; - } } @freezed diff --git a/style/lib/button/icon_primary_button.dart b/style/lib/button/icon_primary_button.dart index b0d101ba..0b632fe4 100644 --- a/style/lib/button/icon_primary_button.dart +++ b/style/lib/button/icon_primary_button.dart @@ -1,14 +1,11 @@ import 'package:flutter/material.dart'; - -import '../theme/colors.dart'; -import '../theme/theme.dart'; +import 'package:style/extenstions/context_extenstions.dart'; class IconPrimaryButton extends StatelessWidget { final Function() onTap; final bool progress; final bool enabled; final Widget icon; - final Color? iconColor; final double size; final double radius; final Color? bgColor; @@ -19,16 +16,14 @@ class IconPrimaryButton extends StatelessWidget { this.progress = true, this.enabled = true, required this.icon, - this.iconColor, - this.backgroundColor, + this.bgColor, this.size = 40.0, this.radius = 30, }); @override Widget build(BuildContext context) { - final AppColorScheme colorScheme = appColorSchemeOf(context); - final bg = backgroundColor ?? colorScheme.containerLow; + final bg = bgColor ?? context.colorScheme.containerLow; return GestureDetector( onTap: onTap, From 313e1e6bebcdd1f2fa7f58586b4942fb43baf351 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 3 Jul 2024 16:05:42 +0530 Subject: [PATCH 56/65] Minor --- .../ui/flow/home/components/home_top_bar.dart | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/app/lib/ui/flow/home/components/home_top_bar.dart b/app/lib/ui/flow/home/components/home_top_bar.dart index a08cfc8c..16501398 100644 --- a/app/lib/ui/flow/home/components/home_top_bar.dart +++ b/app/lib/ui/flow/home/components/home_top_bar.dart @@ -80,23 +80,25 @@ class _HomeTopBarState extends State with TickerProviderStateMixin { Widget _topBar(BuildContext context) { return IntrinsicHeight( child: Container( - color: expand ? context.colorScheme.surface : null, + padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), + color: context.colorScheme.surface, child: SingleChildScrollView( child: Column( children: [ Row( children: [ _iconButton( - context: context, - icon: Assets.images.icSetting, - visibility: !expand, + context: context, + icon: Assets.images.icSetting, + visibility: !expand, onTap: () { AppRoute.setting.push(context); }), const SizedBox(width: 8), _spaceSelection( context: context, - spaceName: widget.selectedSpace?.space.name ?? context.l10n.home_select_space_text, + spaceName: widget.selectedSpace?.space.name ?? + context.l10n.home_select_space_text, ), const SizedBox(width: 8), _iconButton( @@ -167,8 +169,10 @@ class _HomeTopBarState extends State with TickerProviderStateMixin { .copyWith(color: context.colorScheme.textPrimary), ), ), - if (widget.fetchingInviteCode || (widget.selectedSpace == null && widget.loading)) ...[ - const AppProgressIndicator(size: AppProgressIndicatorSize.small) + if (widget.fetchingInviteCode || + (widget.selectedSpace == null && widget.loading)) ...[ + const AppProgressIndicator( + size: AppProgressIndicatorSize.small) ] else ...[ Icon( expand @@ -230,7 +234,11 @@ class _HomeTopBarState extends State with TickerProviderStateMixin { onSpaceSelected(space); }, child: _spaceListItem( - context, space, index, widget.selectedSpace?.space.id == space.space.id), + context, + space, + index, + widget.selectedSpace?.space.id == space.space.id, + ), ), ); }).toList(), From edc4e50520fa36d5e57e8691617805eb2461b850 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 3 Jul 2024 16:43:39 +0530 Subject: [PATCH 57/65] Fix conflict --- app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart index 07aa926c..43fdc9b7 100644 --- a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart +++ b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart @@ -116,7 +116,7 @@ class _LocateOnMapViewState extends ConsumerState { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), child: IconPrimaryButton( - backgroundColor: context.colorScheme.onPrimary, + bgColor: context.colorScheme.onPrimary, onTap: () {}, icon: SvgPicture.asset( Assets.images.icRelocateIcon, From 6e914327c5de834415701bf2706c53cbd0cecdd8 Mon Sep 17 00:00:00 2001 From: kaushik Date: Wed, 3 Jul 2024 16:59:42 +0530 Subject: [PATCH 58/65] Fix conflict --- app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart index e30929ab..2a9cd634 100644 --- a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart +++ b/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart @@ -114,7 +114,7 @@ class _LocateOnMapViewState extends ConsumerState { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), child: IconPrimaryButton( - backgroundColor: context.colorScheme.onPrimary, + bgColor: context.colorScheme.onPrimary, onTap: () {}, icon: SvgPicture.asset( Assets.images.icRelocateIcon, From ed76761bd1449e9dab980c4a691333adb8290aa4 Mon Sep 17 00:00:00 2001 From: kaushik Date: Thu, 4 Jul 2024 10:48:18 +0530 Subject: [PATCH 59/65] Minor and mr changes --- app/assets/images/ic_search_icon.svg | 5 + app/lib/gen/assets.gen.dart | 4 + app/lib/ui/app_route.dart | 16 ++-- ...ce_view.dart => add_new_place_screen.dart} | 46 +++++----- ...ap_view.dart => locate_on_map_screen.dart} | 10 +- ...iew.dart => choose_place_name_screen.dart} | 92 +++++++++---------- .../choose_place_name_view_model.dart | 20 +++- .../choose_place_name_view_model.freezed.dart | 44 ++++++++- ...list_view.dart => places_list_screen.dart} | 18 ++-- app/lib/ui/flow/home/home_screen.dart | 4 +- .../map/{map_view.dart => map_screen.dart} | 10 +- app/lib/ui/flow/home/map/map_view_model.dart | 2 +- style/lib/text/app_text_field.dart | 78 ++++++++-------- 13 files changed, 204 insertions(+), 145 deletions(-) create mode 100644 app/assets/images/ic_search_icon.svg rename app/lib/ui/flow/geofence/add/addnew/{add_new_place_view.dart => add_new_place_screen.dart} (83%) rename app/lib/ui/flow/geofence/add/locate/{locate_on_map_view.dart => locate_on_map_screen.dart} (92%) rename app/lib/ui/flow/geofence/add/placename/{choose_place_name_view.dart => choose_place_name_screen.dart} (78%) rename app/lib/ui/flow/geofence/places/{places_list_view.dart => places_list_screen.dart} (95%) rename app/lib/ui/flow/home/map/{map_view.dart => map_screen.dart} (98%) diff --git a/app/assets/images/ic_search_icon.svg b/app/assets/images/ic_search_icon.svg new file mode 100644 index 00000000..2cea529e --- /dev/null +++ b/app/assets/images/ic_search_icon.svg @@ -0,0 +1,5 @@ + + + diff --git a/app/lib/gen/assets.gen.dart b/app/lib/gen/assets.gen.dart index 07ca8ada..2b2ba3ba 100644 --- a/app/lib/gen/assets.gen.dart +++ b/app/lib/gen/assets.gen.dart @@ -98,6 +98,9 @@ class $AssetsImagesGen { /// File path: assets/images/ic_remove.svg String get icRemove => 'assets/images/ic_remove.svg'; + /// File path: assets/images/ic_search_icon.svg + String get icSearchIcon => 'assets/images/ic_search_icon.svg'; + /// File path: assets/images/ic_send_message.svg String get icSendMessage => 'assets/images/ic_send_message.svg'; @@ -154,6 +157,7 @@ class $AssetsImagesGen { icPrivacyPolicy, icRelocateIcon, icRemove, + icSearchIcon, icSendMessage, icSetting, icSignOut, diff --git a/app/lib/ui/app_route.dart b/app/lib/ui/app_route.dart index 2670993b..5143cd76 100644 --- a/app/lib/ui/app_route.dart +++ b/app/lib/ui/app_route.dart @@ -6,9 +6,9 @@ import 'package:flutter/cupertino.dart'; import 'package:go_router/go_router.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:yourspace_flutter/ui/flow/auth/sign_in/phone/verification/phone_verification_screen.dart'; -import 'package:yourspace_flutter/ui/flow/geofence/add/locate/locate_on_map_view.dart'; -import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_name_view.dart'; -import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_view.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/add/locate/locate_on_map_screen.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_name_screen.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_screen.dart'; import 'package:yourspace_flutter/ui/flow/message/chat/chat_screen.dart'; import 'package:yourspace_flutter/ui/flow/message/thread_list_screen.dart'; import 'package:yourspace_flutter/ui/flow/onboard/pick_name_screen.dart'; @@ -23,7 +23,7 @@ import 'package:yourspace_flutter/ui/flow/space/join/join_space_screen.dart'; import 'flow/auth/sign_in/phone/sign_in_with_phone_screen.dart'; import 'flow/auth/sign_in/sign_in_method_screen.dart'; -import 'flow/geofence/add/addnew/add_new_place_view.dart'; +import 'flow/geofence/add/addnew/add_new_place_screen.dart'; import 'flow/home/home_screen.dart'; import 'flow/intro/intro_screen.dart'; @@ -176,25 +176,25 @@ class AppRoute { static AppRoute placesList(String spaceId) { return AppRoute(pathPlacesList, - builder: (_) => PlacesListView(spaceId: spaceId)); + builder: (_) => PlacesListScreen(spaceId: spaceId)); } static AppRoute addNewPlace(String spaceId) { return AppRoute( pathAddNewPlace, - builder: (_) => AddNewPlaceView(spaceId: spaceId), + builder: (_) => AddNewPlaceScreen(spaceId: spaceId), ); } static AppRoute locateOnMapScreen(String spaceId) { return AppRoute(pathLocateOnMap, - builder: (_) => LocateOnMapView(spaceId: spaceId)); + builder: (_) => LocateOnMapScreen(spaceId: spaceId)); } static AppRoute choosePlaceName(LatLng location, String spaceId) { return AppRoute( pathChoosePlace, - builder: (_) => ChoosePlaceNameView( + builder: (_) => ChoosePlaceNameScreen( location: location, spaceId: spaceId, ), diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_screen.dart similarity index 83% rename from app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart rename to app/lib/ui/flow/geofence/add/addnew/add_new_place_screen.dart index 4cd17f1f..7c2eeedf 100644 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_view.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_screen.dart @@ -6,6 +6,7 @@ import 'package:style/animation/on_tap_scale.dart'; import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/indicator/progress_indicator.dart'; import 'package:style/text/app_text_dart.dart'; +import 'package:style/text/app_text_field.dart'; import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; import 'package:yourspace_flutter/ui/app_route.dart'; import 'package:yourspace_flutter/ui/components/app_page.dart'; @@ -14,16 +15,16 @@ import '../../../../../gen/assets.gen.dart'; import '../../../../components/error_snakebar.dart'; import 'add_new_place_view_model.dart'; -class AddNewPlaceView extends ConsumerStatefulWidget { +class AddNewPlaceScreen extends ConsumerStatefulWidget { final String spaceId; - const AddNewPlaceView({super.key, required this.spaceId}); + const AddNewPlaceScreen({super.key, required this.spaceId}); @override - ConsumerState createState() => _AddNewPlaceViewState(); + ConsumerState createState() => _AddNewPlaceViewState(); } -class _AddNewPlaceViewState extends ConsumerState { +class _AddNewPlaceViewState extends ConsumerState { late AddNewPlaceViewNotifier notifier; @override @@ -78,32 +79,29 @@ class _AddNewPlaceViewState extends ConsumerState { Widget _searchTextField() { return Column( children: [ - TextField( - style: AppTextStyle.subtitle3, + AppTextField( + style: AppTextStyle.subtitle3.copyWith( + color: context.colorScheme.textPrimary, + ), onChanged: (value) { notifier.onPlaceNameChanged(value.trim()); }, - decoration: InputDecoration( - prefixIcon: Padding( - padding: const EdgeInsets.only(right: 8), - child: Icon( - Icons.search, - color: context.colorScheme.textDisabled, + prefixIcon: Padding( + padding: const EdgeInsets.only(right: 8, bottom: 8), + child: SvgPicture.asset( + Assets.images.icSearchIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.textDisabled, + BlendMode.srcATop, ), ), - hintText: context.l10n.add_new_place_search_hint_text, - hintStyle: AppTextStyle.subtitle3.copyWith( - color: context.colorScheme.textDisabled, - ), - contentPadding: const EdgeInsets.symmetric(vertical: 0), - prefixIconConstraints: const BoxConstraints(), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide(color: context.colorScheme.outline), - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: context.colorScheme.primary), - ), ), + hintText: context.l10n.add_new_place_search_hint_text, + hintStyle: AppTextStyle.subtitle3.copyWith( + color: context.colorScheme.textDisabled, + ), + isDense: true, + contentPadding: const EdgeInsets.all(0), ), ], ); diff --git a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart b/app/lib/ui/flow/geofence/add/locate/locate_on_map_screen.dart similarity index 92% rename from app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart rename to app/lib/ui/flow/geofence/add/locate/locate_on_map_screen.dart index 43fdc9b7..4e8f1076 100644 --- a/app/lib/ui/flow/geofence/add/locate/locate_on_map_view.dart +++ b/app/lib/ui/flow/geofence/add/locate/locate_on_map_screen.dart @@ -12,18 +12,18 @@ import 'package:yourspace_flutter/ui/components/app_page.dart'; import 'package:yourspace_flutter/ui/flow/geofence/add/locate/locate_on_map_view_model.dart'; import '../../../../../gen/assets.gen.dart'; -import '../../../home/map/map_view.dart'; +import '../../../home/map/map_screen.dart'; -class LocateOnMapView extends ConsumerStatefulWidget { +class LocateOnMapScreen extends ConsumerStatefulWidget { final String spaceId; - const LocateOnMapView({super.key, required this.spaceId}); + const LocateOnMapScreen({super.key, required this.spaceId}); @override - ConsumerState createState() => _LocateOnMapViewState(); + ConsumerState createState() => _LocateOnMapViewState(); } -class _LocateOnMapViewState extends ConsumerState { +class _LocateOnMapViewState extends ConsumerState { late LocateOnMapVieNotifier notifier; final _cameraPosition = const CameraPosition(target: LatLng(0.0, 0.0), zoom: defaultCameraZoom); diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_screen.dart similarity index 78% rename from app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart rename to app/lib/ui/flow/geofence/add/placename/choose_place_name_screen.dart index 0e23050f..d53c92fa 100644 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view.dart +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_screen.dart @@ -6,6 +6,7 @@ import 'package:style/animation/on_tap_scale.dart'; import 'package:style/button/primary_button.dart'; import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/text/app_text_dart.dart'; +import 'package:style/text/app_text_field.dart'; import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; import 'package:yourspace_flutter/ui/app_route.dart'; import 'package:yourspace_flutter/ui/components/app_page.dart'; @@ -14,26 +15,25 @@ import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_na import '../../../../../domain/extenstions/widget_extensions.dart'; import '../../../../../gen/assets.gen.dart'; import '../../../../components/error_snakebar.dart'; -import '../../../home/map/map_view.dart'; +import '../../../home/map/map_screen.dart'; -class ChoosePlaceNameView extends ConsumerStatefulWidget { +class ChoosePlaceNameScreen extends ConsumerStatefulWidget { final LatLng location; final String spaceId; - const ChoosePlaceNameView({ + const ChoosePlaceNameScreen({ super.key, required this.location, required this.spaceId, }); @override - ConsumerState createState() => + ConsumerState createState() => _ChoosePlaceNameViewState(); } -class _ChoosePlaceNameViewState extends ConsumerState { +class _ChoosePlaceNameViewState extends ConsumerState { late ChoosePlaceNameViewNotifier notifier; - final _textController = TextEditingController(); @override void initState() { @@ -46,24 +46,24 @@ class _ChoosePlaceNameViewState extends ConsumerState { @override Widget build(BuildContext context) { + final state = ref.watch(choosePlaceViewStateProvider); + _observeError(); - _observePopToPlacesListScreen(); + _observePopToPlacesListScreen(state.title.text); return AppPage( title: context.l10n.choose_place_screen_title, - body: _body(), + body: _body(state), ); } - Widget _body() { - final state = ref.watch(choosePlaceViewStateProvider); - + Widget _body(ChoosePlaceViewState state) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _searchTextField(), + _searchTextField(state), const SizedBox(height: 40), Text( context.l10n.choose_place_suggestion_text, @@ -71,7 +71,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { .copyWith(color: context.colorScheme.textDisabled), ), const SizedBox(height: 16), - _suggestionsPlaceView(state.suggestions), + _suggestionsPlaceView(state.suggestions, state), const Spacer(), Align( alignment: Alignment.center, @@ -82,46 +82,40 @@ class _ChoosePlaceNameViewState extends ConsumerState { ); } - Widget _searchTextField() { + Widget _searchTextField(ChoosePlaceViewState state) { return Column( children: [ - TextField( - controller: _textController, - onChanged: (value) { - if (value.isEmpty) { - setState(() { - _textController.text = ''; - }); - } - }, - style: AppTextStyle.subtitle3, - decoration: InputDecoration( - prefixIcon: Padding( - padding: const EdgeInsets.only(right: 8), - child: Icon( - Icons.search, - color: context.colorScheme.textDisabled, + AppTextField( + controller: state.title, + onChanged: notifier.onSearchTitleChange, + style: AppTextStyle.subtitle3.copyWith( + color: context.colorScheme.textPrimary, + ), + prefixIcon: Padding( + padding: const EdgeInsets.only(right: 8, bottom: 8), + child: SvgPicture.asset( + Assets.images.icSearchIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.textDisabled, + BlendMode.srcATop, ), ), - hintText: context.l10n.choose_place_search_hint_text, - hintStyle: AppTextStyle.subtitle3.copyWith( - color: context.colorScheme.textDisabled, - ), - contentPadding: const EdgeInsets.symmetric(vertical: 0), - prefixIconConstraints: const BoxConstraints(), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide(color: context.colorScheme.outline), - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: context.colorScheme.primary), - ), ), + hintText: context.l10n.choose_place_search_hint_text, + hintStyle: AppTextStyle.subtitle3.copyWith( + color: context.colorScheme.textDisabled, + ), + isDense: true, + contentPadding: const EdgeInsets.all(0), ), ], ); } - Widget _suggestionsPlaceView(List? suggestions) { + Widget _suggestionsPlaceView( + List? suggestions, + ChoosePlaceViewState state, + ) { if (suggestions == null) return Container(); return Wrap( alignment: WrapAlignment.start, @@ -129,9 +123,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { children: suggestions.map((element) { return OnTapScale( onTap: () { - setState(() { - _textController.text = element; - }); + notifier.onTapSuggestedPlace(element); }, child: Chip( label: Text( @@ -152,7 +144,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { } Widget _addPlaceButtonView(ChoosePlaceViewState state) { - final enable = _textController.text.isNotEmpty && !state.addingPlace; + final enable = state.enableAddBtn && !state.addingPlace; return Padding( padding: EdgeInsets.only(bottom: context.mediaQueryPadding.bottom + 24), @@ -160,7 +152,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { enabled: enable, progress: state.addingPlace, onPressed: () { - notifier.onTapAddPlaceBtn(_textController.text); + notifier.onTapAddPlaceBtn(); }, edgeInsets: const EdgeInsets.symmetric(horizontal: 40, vertical: 16), context.l10n.choose_place_add_place_btn_text, @@ -178,7 +170,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { }); } - void _observePopToPlacesListScreen() { + void _observePopToPlacesListScreen(String title) { ref.listen( choosePlaceViewStateProvider.select((state) => state.popToPlaceList), (_, next) { @@ -187,7 +179,7 @@ class _ChoosePlaceNameViewState extends ConsumerState { context, widget.location.latitude, widget.location.longitude, - _textController.text, + title, ); }); } diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart index 5b3f60d3..0e559b30 100644 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.dart @@ -3,6 +3,7 @@ import 'package:data/log/logger.dart'; import 'package:data/service/place_service.dart'; import 'package:data/service/space_service.dart'; import 'package:data/storage/app_preferences.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; @@ -28,7 +29,7 @@ class ChoosePlaceNameViewNotifier extends StateNotifier { ChoosePlaceNameViewNotifier( this._currentUser, this.placesService, this.spaceService) - : super(const ChoosePlaceViewState()); + : super(ChoosePlaceViewState(title: TextEditingController())); void setData(LatLng position, String spaceId) { final suggestionList = [ @@ -47,7 +48,18 @@ class ChoosePlaceNameViewNotifier extends StateNotifier { state = state.copyWith(suggestions: suggestionList); } - void onTapAddPlaceBtn(String value) async { + void onTapSuggestedPlace(String suggestion) { + state = state.copyWith( + title: TextEditingController(text: suggestion.trim()), + enableAddBtn: suggestion.isNotEmpty, + ); + } + + void onSearchTitleChange(String value) { + state = state.copyWith(enableAddBtn: value.trim().isNotEmpty); + } + + void onTapAddPlaceBtn() async { try { state = state.copyWith(addingPlace: true); final members = await spaceService.getMemberBySpaceId(_spaceId!); @@ -55,7 +67,7 @@ class ChoosePlaceNameViewNotifier extends StateNotifier { await placesService.addPlace( _spaceId!, - value, + state.title.text, _location!.latitude, _location!.longitude, _currentUser!.id, @@ -78,6 +90,8 @@ class ChoosePlaceNameViewNotifier extends StateNotifier { class ChoosePlaceViewState with _$ChoosePlaceViewState { const factory ChoosePlaceViewState({ @Default(false) addingPlace, + @Default(false) enableAddBtn, + required TextEditingController title, List? suggestions, Object? error, DateTime? popToPlaceList, diff --git a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart index 2bc9b0e7..4d0bf9a8 100644 --- a/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart +++ b/app/lib/ui/flow/geofence/add/placename/choose_place_name_view_model.freezed.dart @@ -17,6 +17,8 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$ChoosePlaceViewState { dynamic get addingPlace => throw _privateConstructorUsedError; + dynamic get enableAddBtn => throw _privateConstructorUsedError; + TextEditingController get title => throw _privateConstructorUsedError; List? get suggestions => throw _privateConstructorUsedError; Object? get error => throw _privateConstructorUsedError; DateTime? get popToPlaceList => throw _privateConstructorUsedError; @@ -34,6 +36,8 @@ abstract class $ChoosePlaceViewStateCopyWith<$Res> { @useResult $Res call( {dynamic addingPlace, + dynamic enableAddBtn, + TextEditingController title, List? suggestions, Object? error, DateTime? popToPlaceList}); @@ -54,6 +58,8 @@ class _$ChoosePlaceViewStateCopyWithImpl<$Res, @override $Res call({ Object? addingPlace = freezed, + Object? enableAddBtn = freezed, + Object? title = null, Object? suggestions = freezed, Object? error = freezed, Object? popToPlaceList = freezed, @@ -63,6 +69,14 @@ class _$ChoosePlaceViewStateCopyWithImpl<$Res, ? _value.addingPlace : addingPlace // ignore: cast_nullable_to_non_nullable as dynamic, + enableAddBtn: freezed == enableAddBtn + ? _value.enableAddBtn + : enableAddBtn // ignore: cast_nullable_to_non_nullable + as dynamic, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as TextEditingController, suggestions: freezed == suggestions ? _value.suggestions : suggestions // ignore: cast_nullable_to_non_nullable @@ -86,6 +100,8 @@ abstract class _$$ChoosePlaceViewStateImplCopyWith<$Res> @useResult $Res call( {dynamic addingPlace, + dynamic enableAddBtn, + TextEditingController title, List? suggestions, Object? error, DateTime? popToPlaceList}); @@ -103,12 +119,20 @@ class __$$ChoosePlaceViewStateImplCopyWithImpl<$Res> @override $Res call({ Object? addingPlace = freezed, + Object? enableAddBtn = freezed, + Object? title = null, Object? suggestions = freezed, Object? error = freezed, Object? popToPlaceList = freezed, }) { return _then(_$ChoosePlaceViewStateImpl( addingPlace: freezed == addingPlace ? _value.addingPlace! : addingPlace, + enableAddBtn: + freezed == enableAddBtn ? _value.enableAddBtn! : enableAddBtn, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as TextEditingController, suggestions: freezed == suggestions ? _value._suggestions : suggestions // ignore: cast_nullable_to_non_nullable @@ -127,6 +151,8 @@ class __$$ChoosePlaceViewStateImplCopyWithImpl<$Res> class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { const _$ChoosePlaceViewStateImpl( {this.addingPlace = false, + this.enableAddBtn = false, + required this.title, final List? suggestions, this.error, this.popToPlaceList}) @@ -135,6 +161,11 @@ class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { @override @JsonKey() final dynamic addingPlace; + @override + @JsonKey() + final dynamic enableAddBtn; + @override + final TextEditingController title; final List? _suggestions; @override List? get suggestions { @@ -152,7 +183,7 @@ class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { @override String toString() { - return 'ChoosePlaceViewState(addingPlace: $addingPlace, suggestions: $suggestions, error: $error, popToPlaceList: $popToPlaceList)'; + return 'ChoosePlaceViewState(addingPlace: $addingPlace, enableAddBtn: $enableAddBtn, title: $title, suggestions: $suggestions, error: $error, popToPlaceList: $popToPlaceList)'; } @override @@ -162,6 +193,9 @@ class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { other is _$ChoosePlaceViewStateImpl && const DeepCollectionEquality() .equals(other.addingPlace, addingPlace) && + const DeepCollectionEquality() + .equals(other.enableAddBtn, enableAddBtn) && + (identical(other.title, title) || other.title == title) && const DeepCollectionEquality() .equals(other._suggestions, _suggestions) && const DeepCollectionEquality().equals(other.error, error) && @@ -173,6 +207,8 @@ class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { int get hashCode => Object.hash( runtimeType, const DeepCollectionEquality().hash(addingPlace), + const DeepCollectionEquality().hash(enableAddBtn), + title, const DeepCollectionEquality().hash(_suggestions), const DeepCollectionEquality().hash(error), popToPlaceList); @@ -189,6 +225,8 @@ class _$ChoosePlaceViewStateImpl implements _ChoosePlaceViewState { abstract class _ChoosePlaceViewState implements ChoosePlaceViewState { const factory _ChoosePlaceViewState( {final dynamic addingPlace, + final dynamic enableAddBtn, + required final TextEditingController title, final List? suggestions, final Object? error, final DateTime? popToPlaceList}) = _$ChoosePlaceViewStateImpl; @@ -196,6 +234,10 @@ abstract class _ChoosePlaceViewState implements ChoosePlaceViewState { @override dynamic get addingPlace; @override + dynamic get enableAddBtn; + @override + TextEditingController get title; + @override List? get suggestions; @override Object? get error; diff --git a/app/lib/ui/flow/geofence/places/places_list_view.dart b/app/lib/ui/flow/geofence/places/places_list_screen.dart similarity index 95% rename from app/lib/ui/flow/geofence/places/places_list_view.dart rename to app/lib/ui/flow/geofence/places/places_list_screen.dart index b8eefe06..6965eeaa 100644 --- a/app/lib/ui/flow/geofence/places/places_list_view.dart +++ b/app/lib/ui/flow/geofence/places/places_list_screen.dart @@ -15,16 +15,16 @@ import '../../../../domain/extenstions/widget_extensions.dart'; import '../../../../gen/assets.gen.dart'; import '../../../components/error_snakebar.dart'; -class PlacesListView extends ConsumerStatefulWidget { +class PlacesListScreen extends ConsumerStatefulWidget { final String spaceId; - const PlacesListView({super.key, required this.spaceId}); + const PlacesListScreen({super.key, required this.spaceId}); @override - ConsumerState createState() => _PlacesViewState(); + ConsumerState createState() => _PlacesViewState(); } -class _PlacesViewState extends ConsumerState { +class _PlacesViewState extends ConsumerState { late PlacesListViewNotifier notifier; @override @@ -225,11 +225,11 @@ class _PlacesViewState extends ConsumerState { void _observeError() { ref.listen(placesListViewStateProvider.select((state) => state.error), - (previous, next) { - if (next != null) { - showErrorSnackBar(context, next.toString()); - } - }); + (previous, next) { + if (next != null) { + showErrorSnackBar(context, next.toString()); + } + }); } void _observeShowDeletePlaceDialog() { diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index df67d590..8d4f56d7 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -12,7 +12,7 @@ import 'package:yourspace_flutter/ui/flow/home/map/map_view_model.dart'; import '../../components/permission_dialog.dart'; import 'components/home_top_bar.dart'; -import 'map/map_view.dart'; +import 'map/map_screen.dart'; class HomeScreen extends ConsumerStatefulWidget { const HomeScreen({super.key}); @@ -63,7 +63,7 @@ class _HomeScreenState extends ConsumerState { padding: context.mediaQueryPadding, child: Stack( children: [ - MapView(space: state.selectedSpace), + MapScreen(space: state.selectedSpace), HomeTopBar( spaces: state.spaceList, onSpaceItemTap: (name) => notifier.updateSelectedSpace(name), diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_screen.dart similarity index 98% rename from app/lib/ui/flow/home/map/map_view.dart rename to app/lib/ui/flow/home/map/map_screen.dart index 3d986896..66776ee0 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_screen.dart @@ -22,16 +22,16 @@ const defaultCameraZoomForSelectedUser = 17.0; const markerSize = 100.0; const placeSize = 80; -class MapView extends ConsumerStatefulWidget { +class MapScreen extends ConsumerStatefulWidget { final SpaceInfo? space; - const MapView({super.key, this.space}); + const MapScreen({super.key, this.space}); @override - ConsumerState createState() => _MapScreenState(); + ConsumerState createState() => _MapScreenState(); } -class _MapScreenState extends ConsumerState { +class _MapScreenState extends ConsumerState { late MapViewNotifier notifier; GoogleMapController? _controller; final _cameraPosition = @@ -42,7 +42,7 @@ class _MapScreenState extends ConsumerState { List _places = []; @override - void didUpdateWidget(covariant MapView oldWidget) { + void didUpdateWidget(covariant MapScreen oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.space?.space.id != widget.space?.space.id) { setState(() { diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index 563ce0e5..25664559 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -15,7 +15,7 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:image/image.dart' as img; -import 'map_view.dart'; +import 'map_screen.dart'; part 'map_view_model.freezed.dart'; diff --git a/style/lib/text/app_text_field.dart b/style/lib/text/app_text_field.dart index 06894241..50d93f5d 100644 --- a/style/lib/text/app_text_field.dart +++ b/style/lib/text/app_text_field.dart @@ -7,6 +7,7 @@ class AppTextField extends StatelessWidget { final String? label; final TextStyle? labelStyle; final TextEditingController? controller; + final Widget? prefixIcon; final int? maxLines; final int? minLines; final TextStyle? style; @@ -33,6 +34,7 @@ class AppTextField extends StatelessWidget { this.label, this.labelStyle, this.controller, + this.prefixIcon, this.maxLines = 1, this.minLines, this.style, @@ -79,44 +81,46 @@ class AppTextField extends StatelessWidget { } Widget _textField(BuildContext context) => Material( - color: Colors.transparent, - child: TextField( - controller: controller, - onChanged: onChanged, - enabled: enabled, - maxLines: maxLines, - minLines: minLines, - expands: expands, - textInputAction: textInputAction, - autofocus: autoFocus, - keyboardType: keyboardType, - focusNode: focusNode, - textAlign: textAlign, - style: style ?? - AppTextStyle.subtitle2.copyWith( - color: context.colorScheme.textPrimary, - ), - onTapOutside: onTapOutside ?? + color: Colors.transparent, + child: TextField( + controller: controller, + onChanged: onChanged, + enabled: enabled, + maxLines: maxLines, + minLines: minLines, + expands: expands, + textInputAction: textInputAction, + autofocus: autoFocus, + keyboardType: keyboardType, + focusNode: focusNode, + textAlign: textAlign, + style: style ?? + AppTextStyle.subtitle2.copyWith( + color: context.colorScheme.textPrimary, + ), + onTapOutside: onTapOutside ?? (event) { - FocusManager.instance.primaryFocus?.unfocus(); - }, - decoration: InputDecoration( - isDense: isDense, - isCollapsed: isCollapsed, - hintText: hintText, - hintStyle: hintStyle, - focusedBorder: _border(context, true, borderRadius ?? 8), - enabledBorder: _border(context, false, borderRadius ?? 8), - contentPadding: contentPadding ?? - (borderType == AppTextFieldBorderType.outline - ? const EdgeInsets.symmetric( - horizontal: 12, - vertical: 12, - ) - : null), - ), - ), - ); + FocusManager.instance.primaryFocus?.unfocus(); + }, + decoration: InputDecoration( + isDense: isDense, + isCollapsed: isCollapsed, + hintText: hintText, + hintStyle: hintStyle, + prefixIcon: prefixIcon, + prefixIconConstraints: const BoxConstraints(), + focusedBorder: _border(context, true, borderRadius ?? 8), + enabledBorder: _border(context, false, borderRadius ?? 8), + contentPadding: contentPadding ?? + (borderType == AppTextFieldBorderType.outline + ? const EdgeInsets.symmetric( + horizontal: 12, + vertical: 12, + ) + : null), + ), + ), + ); InputBorder _border(BuildContext context, bool focused, double borderRadius) { switch (borderType) { From cc72a4d736c0ded46abf4051f4dbd16a2bbdba28 Mon Sep 17 00:00:00 2001 From: kaushik Date: Thu, 4 Jul 2024 12:34:24 +0530 Subject: [PATCH 60/65] Fix typo --- app/lib/ui/app_route.dart | 4 +- .../edit/components/place_marker.dart | 17 ++-- ...place_view.dart => edit_place_screen.dart} | 52 ++++++------ .../geofence/edit/edit_place_view_model.dart | 71 ++++++++++------ data/lib/config.dart | 6 ++ style/lib/text/app_text_field.dart | 81 ++++++++++--------- 6 files changed, 127 insertions(+), 104 deletions(-) rename app/lib/ui/flow/geofence/edit/{edit_place_view.dart => edit_place_screen.dart} (92%) create mode 100644 data/lib/config.dart diff --git a/app/lib/ui/app_route.dart b/app/lib/ui/app_route.dart index 6f09e919..b02bc267 100644 --- a/app/lib/ui/app_route.dart +++ b/app/lib/ui/app_route.dart @@ -9,7 +9,7 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:yourspace_flutter/ui/flow/auth/sign_in/phone/verification/phone_verification_screen.dart'; import 'package:yourspace_flutter/ui/flow/geofence/add/locate/locate_on_map_view.dart'; import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_name_view.dart'; -import 'package:yourspace_flutter/ui/flow/geofence/edit/edit_place_view.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/edit/edit_place_screen.dart'; import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_view.dart'; import 'package:yourspace_flutter/ui/flow/message/chat/chat_screen.dart'; import 'package:yourspace_flutter/ui/flow/message/thread_list_screen.dart'; @@ -207,7 +207,7 @@ class AppRoute { static AppRoute editPlaceScreen(ApiPlace place) { return AppRoute( pathEditPlace, - builder: (_) => EditPlaceView(place: place), + builder: (_) => EditPlaceScreen(place: place), ); } diff --git a/app/lib/ui/flow/geofence/edit/components/place_marker.dart b/app/lib/ui/flow/geofence/edit/components/place_marker.dart index 2a8016a3..a5bd008e 100644 --- a/app/lib/ui/flow/geofence/edit/components/place_marker.dart +++ b/app/lib/ui/flow/geofence/edit/components/place_marker.dart @@ -5,16 +5,11 @@ import 'package:style/extenstions/context_extenstions.dart'; import '../../../../../gen/assets.gen.dart'; -class PlaceMarker extends StatefulWidget { +class PlaceMarker extends StatelessWidget { final double radius; const PlaceMarker({super.key, required this.radius}); - @override - State createState() => _PlaceMarkerState(); -} - -class _PlaceMarkerState extends State { @override Widget build(BuildContext context) { return Stack( @@ -22,14 +17,14 @@ class _PlaceMarkerState extends State { children: [ ClipRect( child: OverflowBox( - maxHeight: widget.radius, - maxWidth: widget.radius, + maxHeight: radius, + maxWidth: radius, child: AnimatedContainer( duration: const Duration(milliseconds: 300), - width: widget.radius, - height: widget.radius, + width: radius, + height: radius, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(widget.radius), + borderRadius: BorderRadius.circular(radius), color: context.colorScheme.primary.withOpacity(0.5), ), ), diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view.dart b/app/lib/ui/flow/geofence/edit/edit_place_screen.dart similarity index 92% rename from app/lib/ui/flow/geofence/edit/edit_place_view.dart rename to app/lib/ui/flow/geofence/edit/edit_place_screen.dart index 9123c9b2..3d045b70 100644 --- a/app/lib/ui/flow/geofence/edit/edit_place_view.dart +++ b/app/lib/ui/flow/geofence/edit/edit_place_screen.dart @@ -14,6 +14,7 @@ import 'package:style/button/primary_button.dart'; import 'package:style/extenstions/context_extenstions.dart'; import 'package:style/indicator/progress_indicator.dart'; import 'package:style/text/app_text_dart.dart'; +import 'package:style/text/app_text_field.dart'; import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; import 'package:yourspace_flutter/ui/components/app_page.dart'; import 'package:yourspace_flutter/ui/flow/geofence/edit/edit_place_view_model.dart'; @@ -24,16 +25,18 @@ import '../../../components/error_snakebar.dart'; import '../../../components/user_profile_image.dart'; import 'components/place_marker.dart'; -class EditPlaceView extends ConsumerStatefulWidget { +const defaultCameraZoom = 15.7; + +class EditPlaceScreen extends ConsumerStatefulWidget { final ApiPlace place; - const EditPlaceView({super.key, required this.place}); + const EditPlaceScreen({super.key, required this.place}); @override - ConsumerState createState() => _EditPlaceViewState(); + ConsumerState createState() => _EditPlaceViewState(); } -class _EditPlaceViewState extends ConsumerState { +class _EditPlaceViewState extends ConsumerState { late EditPlaceViewNotifier notifier; late CameraPosition _cameraPosition; GoogleMapController? _controller; @@ -47,7 +50,7 @@ class _EditPlaceViewState extends ConsumerState { _textController = TextEditingController(text: widget.place.name); _cameraPosition = CameraPosition( target: LatLng(widget.place.latitude, widget.place.longitude), - zoom: 16); + zoom: defaultCameraZoom); runPostFrame(() { notifier = ref.watch(editPlaceViewStateProvider.notifier); @@ -74,6 +77,7 @@ class _EditPlaceViewState extends ConsumerState { child: state.saving ? const AppProgressIndicator(size: AppProgressIndicatorSize.small) : OnTapScale( + enabled: state.enableSave, onTap: () { notifier.onSavePlace(); }, @@ -207,8 +211,8 @@ class _EditPlaceViewState extends ConsumerState { .copyWith(color: context.colorScheme.textDisabled), ), const SizedBox(height: 16), - _placeTextField(place.name, Icons.bookmark, state.isAdmin), - const SizedBox(height: 16), + _placeTextField(place.name, state.isAdmin), + const SizedBox(height: 24), _placeAddressView(address), const SizedBox(height: 8), Divider(thickness: 1, height: 1, color: context.colorScheme.outline) @@ -217,13 +221,13 @@ class _EditPlaceViewState extends ConsumerState { ); } - Widget _placeTextField(String placeName, IconData iconData, bool isAdmin) { + Widget _placeTextField(String placeName, bool isAdmin) { return Column( children: [ - TextField( + AppTextField( controller: _textController, enabled: isAdmin, - style: AppTextStyle.subtitle3 + style: AppTextStyle.subtitle2 .copyWith(color: context.colorScheme.textPrimary), onChanged: (value) { notifier.onPlaceNameChanged(value.trim()); @@ -231,23 +235,16 @@ class _EditPlaceViewState extends ConsumerState { onTapOutside: (event) { FocusManager.instance.primaryFocus?.unfocus(); }, - decoration: InputDecoration( - prefixIcon: Padding( - padding: const EdgeInsets.only(right: 8), - child: Icon( - iconData, - color: context.colorScheme.textPrimary, - ), - ), - contentPadding: const EdgeInsets.symmetric(vertical: 0), - prefixIconConstraints: const BoxConstraints(), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide(color: context.colorScheme.outline), - ), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: context.colorScheme.primary), + prefixIcon: Padding( + padding: const EdgeInsets.only(right: 8, bottom: 8), + child: Icon( + Icons.bookmark, + size: 24, + color: context.colorScheme.textPrimary, ), ), + isDense: true, + contentPadding: const EdgeInsets.all(0), ), ], ); @@ -264,7 +261,7 @@ class _EditPlaceViewState extends ConsumerState { Expanded( child: Text( address, - style: AppTextStyle.subtitle3 + style: AppTextStyle.subtitle2 .copyWith(color: context.colorScheme.textPrimary), overflow: TextOverflow.ellipsis, maxLines: 1, @@ -452,7 +449,7 @@ class _EditPlaceViewState extends ConsumerState { double _getZoomLevel(double radius) { double scale = radius / 200; - double zoomLevel = 16 - math.log(scale) / math.log(2); + double zoomLevel = defaultCameraZoom - math.log(scale) / math.log(2); return zoomLevel; } @@ -460,6 +457,7 @@ class _EditPlaceViewState extends ConsumerState { LatLng latLang, double radius, ) async { + if (_controller == null) return; final zoom = await _controller?.getZoomLevel(); if (zoom == _previousZoom) return; const double earthRadius = 6378100.0; diff --git a/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart b/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart index 0e1c78a5..fb13cd21 100644 --- a/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart +++ b/app/lib/ui/flow/geofence/edit/edit_place_view_model.dart @@ -55,7 +55,7 @@ class EditPlaceViewNotifier extends StateNotifier { isAdmin: place.created_by == _currentUser.id, loading: false, ); - getAddress(place.latitude, place.longitude); + _getAddress(place.latitude, place.longitude); } catch (error, stack) { state = state.copyWith(loading: false, error: error); logger.e( @@ -66,7 +66,7 @@ class EditPlaceViewNotifier extends StateNotifier { } } - void getAddress(double latitude, double longitude) async { + void _getAddress(double latitude, double longitude) async { if (state.gettingAddress) return; state = state.copyWith(gettingAddress: true); @@ -83,15 +83,15 @@ class EditPlaceViewNotifier extends StateNotifier { ?.copyWith(latitude: target.latitude, longitude: target.longitude); state = state.copyWith(updatedPlace: updatePlace); - getAddress(target.latitude, target.longitude); - enableSaveBtn(); + _getAddress(target.latitude, target.longitude); + _enableSaveBtn(); } void onPlaceRadiusChanged(double value) { if (state.updatedPlace == null) return; final updatePlace = state.updatedPlace?.copyWith(radius: value); - state = state.copyWith(updatedPlace: updatePlace,radius: value); - enableSaveBtn(); + state = state.copyWith(updatedPlace: updatePlace, radius: value); + _enableSaveBtn(); } void onPlaceNameChanged(String value) { @@ -100,39 +100,58 @@ class EditPlaceViewNotifier extends StateNotifier { } void onToggleArrives(String userId, bool arrives) { - final arrivesList = - List.from(state.updatedSetting?.arrival_alert_for ?? []); - if (arrivesList.isNotEmpty) { - if (arrives) { - arrivesList.add(userId); - } else { - arrivesList.remove(userId); - } + if (state.updatedSetting != null) { + final List arrivesList = + List.from(state.updatedSetting!.arrival_alert_for); + + arrives ? arrivesList.add(userId) : arrivesList.remove(userId); + final updatedSettings = state.updatedSetting?.copyWith(arrival_alert_for: arrivesList); state = state.copyWith(updatedSetting: updatedSettings); + } else { + _updateMemberSetting(userId: userId, isArrives: true); } - enableSaveBtn(); + _enableSaveBtn(); } void onToggleLeaves(String userId, bool leaves) { - final leaveList = - List.from(state.updatedSetting?.leave_alert_for ?? []); - if (leaveList.isNotEmpty) { - if (leaves) { - leaveList.add(userId); - } else { - leaveList.remove(userId); - } + if (state.updatedSetting != null) { + final List leaveList = + List.from(state.updatedSetting!.leave_alert_for); + + leaves ? leaveList.add(userId) : leaveList.remove(userId); + final updatedSettings = state.updatedSetting?.copyWith(leave_alert_for: leaveList); state = state.copyWith(updatedSetting: updatedSettings); + } else { + _updateMemberSetting(userId: userId, isLeaves: true); } + + _enableSaveBtn(); + } + + void _updateMemberSetting({ + required String userId, + bool isArrives = false, + bool isLeaves = false, + }) { + final List arrives = isArrives ? [userId] : []; + final List leaves = isLeaves ? [userId] : []; + + final setting = ApiPlaceMemberSetting( + user_id: _currentUser!.id, + place_id: _place!.id, + arrival_alert_for: arrives, + leave_alert_for: leaves, + ); + state = state.copyWith(updatedSetting: setting); } - void enableSaveBtn() { - final isChanged = state.updatedPlace != _place || - (_setting != null && state.updatedSetting != _setting); + void _enableSaveBtn() { + final isChanged = + state.updatedPlace != _place || state.updatedSetting != _setting; state = state.copyWith(enableSave: isChanged); } diff --git a/data/lib/config.dart b/data/lib/config.dart new file mode 100644 index 00000000..2693501c --- /dev/null +++ b/data/lib/config.dart @@ -0,0 +1,6 @@ +class AppConfig { + static const String placeBaseUrl = + 'https://maps.googleapis.com/maps/api/place/textsearch/json'; + + static const String mapApiKey = 'AIzaSyDbaJSVGU4Jkhd_V_e9esorzh_8yykh160'; +} diff --git a/style/lib/text/app_text_field.dart b/style/lib/text/app_text_field.dart index 06894241..13fc41d2 100644 --- a/style/lib/text/app_text_field.dart +++ b/style/lib/text/app_text_field.dart @@ -7,6 +7,7 @@ class AppTextField extends StatelessWidget { final String? label; final TextStyle? labelStyle; final TextEditingController? controller; + final Widget? prefixIcon; final int? maxLines; final int? minLines; final TextStyle? style; @@ -33,6 +34,7 @@ class AppTextField extends StatelessWidget { this.label, this.labelStyle, this.controller, + this.prefixIcon, this.maxLines = 1, this.minLines, this.style, @@ -78,45 +80,48 @@ class AppTextField extends StatelessWidget { ); } - Widget _textField(BuildContext context) => Material( - color: Colors.transparent, - child: TextField( - controller: controller, - onChanged: onChanged, - enabled: enabled, - maxLines: maxLines, - minLines: minLines, - expands: expands, - textInputAction: textInputAction, - autofocus: autoFocus, - keyboardType: keyboardType, - focusNode: focusNode, - textAlign: textAlign, - style: style ?? - AppTextStyle.subtitle2.copyWith( - color: context.colorScheme.textPrimary, + Widget _textField(BuildContext context) => + Material( + color: Colors.transparent, + child: TextField( + controller: controller, + onChanged: onChanged, + enabled: enabled, + maxLines: maxLines, + minLines: minLines, + expands: expands, + textInputAction: textInputAction, + autofocus: autoFocus, + keyboardType: keyboardType, + focusNode: focusNode, + textAlign: textAlign, + style: style ?? + AppTextStyle.subtitle2.copyWith( + color: context.colorScheme.textPrimary, + ), + onTapOutside: onTapOutside ?? + (event) { + FocusManager.instance.primaryFocus?.unfocus(); + }, + decoration: InputDecoration( + isDense: isDense, + isCollapsed: isCollapsed, + hintText: hintText, + hintStyle: hintStyle, + prefixIcon:prefixIcon, + prefixIconConstraints: const BoxConstraints(), + focusedBorder: _border(context, true, borderRadius ?? 8), + enabledBorder: _border(context, false, borderRadius ?? 8), + contentPadding: contentPadding ?? + (borderType == AppTextFieldBorderType.outline + ? const EdgeInsets.symmetric( + horizontal: 12, + vertical: 12, + ) + : null), ), - onTapOutside: onTapOutside ?? - (event) { - FocusManager.instance.primaryFocus?.unfocus(); - }, - decoration: InputDecoration( - isDense: isDense, - isCollapsed: isCollapsed, - hintText: hintText, - hintStyle: hintStyle, - focusedBorder: _border(context, true, borderRadius ?? 8), - enabledBorder: _border(context, false, borderRadius ?? 8), - contentPadding: contentPadding ?? - (borderType == AppTextFieldBorderType.outline - ? const EdgeInsets.symmetric( - horizontal: 12, - vertical: 12, - ) - : null), - ), - ), - ); + ), + ); InputBorder _border(BuildContext context, bool focused, double borderRadius) { switch (borderType) { From 19ce4deee647ed622ba00c00b44bf04efae0b86d Mon Sep 17 00:00:00 2001 From: kaushik Date: Thu, 4 Jul 2024 14:17:19 +0530 Subject: [PATCH 61/65] Mr changes --- app/assets/locales/app_en.arb | 2 +- data/lib/api/space/api_space_service.dart | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/assets/locales/app_en.arb b/app/assets/locales/app_en.arb index 3acedb1e..ac5bc0f4 100644 --- a/app/assets/locales/app_en.arb +++ b/app/assets/locales/app_en.arb @@ -231,7 +231,7 @@ }, "edit_place_title_text": "Edit place", "edit_place_getting_address_text": "Getting Address…", - "edit_place_detail_title_text": "Place detail", + "edit_place_detail_title_text": "Place details", "edit_place_get_notified_title_text": "Get notified when...", "edit_place_arrives_text": "Arrives", "edit_place_leaves_text": "Leaves", diff --git a/data/lib/api/space/api_space_service.dart b/data/lib/api/space/api_space_service.dart index ab162911..05afefae 100644 --- a/data/lib/api/space/api_space_service.dart +++ b/data/lib/api/space/api_space_service.dart @@ -84,13 +84,10 @@ class ApiSpaceService { } Stream> getStreamSpaceMemberBySpaceId(String spaceId) { - return FirebaseFirestore.instance - .collection('spaces') - .doc(spaceId) - .collection('space_members') - .snapshots() - .map((querySnapshot) => querySnapshot.docs - .map((doc) => ApiSpaceMember.fromJson(doc.data())) + return spaceMemberRef(spaceId).snapshots().map((querySnapshot) => + querySnapshot.docs + .map((doc) => + ApiSpaceMember.fromJson(doc.data() as Map)) .toList()); } From 6bfe066fe3c4ae0eb45fee18640db671915880ff Mon Sep 17 00:00:00 2001 From: kaushik Date: Thu, 4 Jul 2024 18:12:55 +0530 Subject: [PATCH 62/65] Fix typo --- app/lib/ui/flow/geofence/edit/edit_place_screen.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/lib/ui/flow/geofence/edit/edit_place_screen.dart b/app/lib/ui/flow/geofence/edit/edit_place_screen.dart index 3d045b70..a2b4372e 100644 --- a/app/lib/ui/flow/geofence/edit/edit_place_screen.dart +++ b/app/lib/ui/flow/geofence/edit/edit_place_screen.dart @@ -181,6 +181,8 @@ class _EditPlaceViewState extends ConsumerState { child: Slider( value: radius, onChanged: notifier.onPlaceRadiusChanged, + activeColor: context.colorScheme.primary, + inactiveColor: context.colorScheme.containerLow, min: 100, max: 3219, divisions: 100, From adc0df514e1737dfe4bd5ba2fc40413cad67e840 Mon Sep 17 00:00:00 2001 From: kaushik Date: Thu, 4 Jul 2024 18:38:08 +0530 Subject: [PATCH 63/65] Fix conflict --- app/lib/ui/app_route.dart | 19 ++++++++++++------- .../add/addnew/add_new_place_screen.dart | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/lib/ui/app_route.dart b/app/lib/ui/app_route.dart index ce867a4f..48774825 100644 --- a/app/lib/ui/app_route.dart +++ b/app/lib/ui/app_route.dart @@ -1,4 +1,3 @@ -import 'package:data/api/place/api_place.dart'; import 'dart:async'; import 'package:data/api/message/message_models.dart'; @@ -8,12 +7,9 @@ import 'package:flutter/cupertino.dart'; import 'package:go_router/go_router.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:yourspace_flutter/ui/flow/auth/sign_in/phone/verification/phone_verification_screen.dart'; -import 'package:yourspace_flutter/ui/flow/geofence/add/locate/locate_on_map_view.dart'; -import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_name_view.dart'; -import 'package:yourspace_flutter/ui/flow/geofence/edit/edit_place_screen.dart'; -import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_view.dart'; import 'package:yourspace_flutter/ui/flow/geofence/add/locate/locate_on_map_screen.dart'; import 'package:yourspace_flutter/ui/flow/geofence/add/placename/choose_place_name_screen.dart'; +import 'package:yourspace_flutter/ui/flow/geofence/edit/edit_place_screen.dart'; import 'package:yourspace_flutter/ui/flow/geofence/places/places_list_screen.dart'; import 'package:yourspace_flutter/ui/flow/message/chat/chat_screen.dart'; import 'package:yourspace_flutter/ui/flow/message/thread_list_screen.dart'; @@ -221,10 +217,19 @@ class AppRoute { builder: (_) => ThreadListScreen(spaceInfo: space), ); } - static AppRoute chat({required SpaceInfo spaceInfo, ThreadInfo? thread, List? threadInfoList}) { + + static AppRoute chat({ + required SpaceInfo spaceInfo, + ThreadInfo? thread, + List? threadInfoList, + }) { return AppRoute( pathMessage, - builder: (_) => ChatScreen(spaceInfo: spaceInfo, threadInfo: thread, threadInfoList: threadInfoList), + builder: (_) => ChatScreen( + spaceInfo: spaceInfo, + threadInfo: thread, + threadInfoList: threadInfoList, + ), ); } diff --git a/app/lib/ui/flow/geofence/add/addnew/add_new_place_screen.dart b/app/lib/ui/flow/geofence/add/addnew/add_new_place_screen.dart index 7c2eeedf..a878a104 100644 --- a/app/lib/ui/flow/geofence/add/addnew/add_new_place_screen.dart +++ b/app/lib/ui/flow/geofence/add/addnew/add_new_place_screen.dart @@ -46,7 +46,7 @@ class _AddNewPlaceViewState extends ConsumerState { padding: EdgeInsets.only( left: 16, right: 16, - bottom: context.mediaQueryPadding.bottom + 24, + bottom: context.mediaQueryPadding.bottom, ), child: SingleChildScrollView( child: Column( From 64e876565e94656888b16f730fb9364fad8b381e Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 5 Jul 2024 12:21:26 +0530 Subject: [PATCH 64/65] Fix typo --- app/lib/ui/flow/home/home_screen.dart | 2 +- app/lib/ui/flow/home/map/map_view_model.dart | 28 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index 00c90965..c9cf18af 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -50,7 +50,7 @@ class _HomeScreenState extends ConsumerState { if(state.selectedSpace != null){ notifier.getAllSpace(); notifier.showBatteryOptimizationDialog(); - mapNotifier.checkLocationAndNotificationPermission(); + mapNotifier.checkUserPermission(); } }, child: _body(context, state), diff --git a/app/lib/ui/flow/home/map/map_view_model.dart b/app/lib/ui/flow/home/map/map_view_model.dart index 563ce0e5..eff6f836 100644 --- a/app/lib/ui/flow/home/map/map_view_model.dart +++ b/app/lib/ui/flow/home/map/map_view_model.dart @@ -43,15 +43,15 @@ class MapViewNotifier extends StateNotifier { ) : super(const MapViewState()); void loadData(String? spaceId) { - onSelectedSpaceChange(); + _onSelectedSpaceChange(); if (spaceId == null) return; - listenMemberLocation(spaceId); - listenPlaces(spaceId); + _listenMemberLocation(spaceId); + _listenPlaces(spaceId); } - void onSelectedSpaceChange() { + void _onSelectedSpaceChange() { state = state.copyWith( userInfo: [], places: [], @@ -61,14 +61,14 @@ class MapViewNotifier extends StateNotifier { ); } - void listenMemberLocation(String spaceId) async { + void _listenMemberLocation(String spaceId) async { if (state.loading) return; try { state = state.copyWith(loading: true, selectedUser: null); spaceService.getMemberWithLocation(spaceId).listen((userInfo) { state = state.copyWith(userInfo: userInfo, loading: false); - userMapPositions(userInfo); + _userMapPositions(userInfo); }); } catch (error, stack) { state = state.copyWith(loading: false, error: error); @@ -80,7 +80,7 @@ class MapViewNotifier extends StateNotifier { } } - void listenPlaces(String spaceId) async { + void _listenPlaces(String spaceId) async { try { placeService.getAllPlacesStream(spaceId).listen((places) { state = state.copyWith(places: places); @@ -94,11 +94,11 @@ class MapViewNotifier extends StateNotifier { } } - void userMapPositions(List userInfo) async { + void _userMapPositions(List userInfo) async { final List markers = []; for (final info in userInfo) { if (info.user.id == _currentUser?.id) { - mapCameraPosition(info); + _mapCameraPosition(info); } if (info.location != null) { @@ -148,7 +148,7 @@ class MapViewNotifier extends StateNotifier { return null; } - void mapCameraPosition(ApiUserInfo userInfo) { + void _mapCameraPosition(ApiUserInfo userInfo) { final position = CameraPosition( target: LatLng(userInfo.location?.latitude ?? 0.0, userInfo.location?.longitude ?? 0.0), @@ -175,7 +175,7 @@ class MapViewNotifier extends StateNotifier { void onDismissMemberDetail() { state = state.copyWith(selectedUser: null, defaultPosition: null); - onShowDetailUpdateUserMarker(null); + _onSelectUserMarker(null); } void showMemberDetail(ApiUserInfo member) { @@ -190,10 +190,10 @@ class MapViewNotifier extends StateNotifier { state = state.copyWith(selectedUser: selectedMember, defaultPosition: position); - onShowDetailUpdateUserMarker(member.user.id); + _onSelectUserMarker(member.user.id); } - void onShowDetailUpdateUserMarker(String? userId) { + void _onSelectUserMarker(String? userId) { final List updatedMarkers; if (userId == null) { @@ -215,7 +215,7 @@ class MapViewNotifier extends StateNotifier { showMemberDetail(user); } - void checkLocationAndNotificationPermission() async { + void checkUserPermission() async { final isLocationEnabled = await permissionService.isLocationAlwaysEnabled(); final isLocationServiceEnabled = await permissionService.isLocationServiceEnabled(); From e0795c0bc7fc0ff583deedfda8118c913a353741 Mon Sep 17 00:00:00 2001 From: kaushik Date: Fri, 5 Jul 2024 13:52:23 +0530 Subject: [PATCH 65/65] Minor --- .../map/components/space_user_footer.dart | 28 ++++++++++++------- app/lib/ui/flow/home/map/map_view.dart | 1 + 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/app/lib/ui/flow/home/map/components/space_user_footer.dart b/app/lib/ui/flow/home/map/components/space_user_footer.dart index 5b2d8d81..1fd51355 100644 --- a/app/lib/ui/flow/home/map/components/space_user_footer.dart +++ b/app/lib/ui/flow/home/map/components/space_user_footer.dart @@ -4,6 +4,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:style/animation/on_tap_scale.dart'; import 'package:style/button/icon_primary_button.dart'; import 'package:style/extenstions/context_extenstions.dart'; +import 'package:style/indicator/progress_indicator.dart'; import 'package:style/text/app_text_dart.dart'; import 'package:yourspace_flutter/domain/extenstions/context_extenstions.dart'; @@ -15,6 +16,7 @@ class SpaceUserFooter extends StatefulWidget { final List? members; final ApiUserInfo? selectedUser; final bool isEnabled; + final bool fetchingInviteCode; final void Function() onAddMemberTap; final void Function(ApiUserInfo) onMemberTap; final void Function() onRelocateTap; @@ -27,6 +29,7 @@ class SpaceUserFooter extends StatefulWidget { required this.members, this.selectedUser, required this.isEnabled, + required this.fetchingInviteCode, required this.onAddMemberTap, required this.onMemberTap, required this.onRelocateTap, @@ -158,6 +161,7 @@ class _SpaceUserFooterState extends State { Widget addMemberView(BuildContext context) { return OnTapScale( + enabled: !widget.fetchingInviteCode, onTap: widget.onAddMemberTap, child: Padding( padding: const EdgeInsets.only(right: 6), @@ -170,16 +174,20 @@ class _SpaceUserFooterState extends State { border: Border.all(color: context.colorScheme.primary, width: 1), borderRadius: BorderRadius.circular(30)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: SvgPicture.asset( - Assets.images.icAddUserIcon, - colorFilter: ColorFilter.mode( - context.colorScheme.primary, - BlendMode.srcATop, - ), - ), - ), + child: widget.fetchingInviteCode + ? const AppProgressIndicator( + size: AppProgressIndicatorSize.small, + ) + : Padding( + padding: const EdgeInsets.all(8.0), + child: SvgPicture.asset( + Assets.images.icAddUserIcon, + colorFilter: ColorFilter.mode( + context.colorScheme.primary, + BlendMode.srcATop, + ), + ), + ), ), const SizedBox(height: 2), Text( diff --git a/app/lib/ui/flow/home/map/map_view.dart b/app/lib/ui/flow/home/map/map_view.dart index e0abcc48..8a17d1ef 100644 --- a/app/lib/ui/flow/home/map/map_view.dart +++ b/app/lib/ui/flow/home/map/map_view.dart @@ -97,6 +97,7 @@ class _MapScreenState extends ConsumerState { members: state.userInfo, selectedUser: state.selectedUser, isEnabled: !state.loading, + fetchingInviteCode: state.fetchingInviteCode, onAddMemberTap: () { notifier.onAddMemberTap(widget.space!.space.id); },