diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index fd501f66..8e69c5e4 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -18,6 +18,8 @@ PODS: - connectivity_plus (0.0.1): - Flutter - FlutterMacOS + - cryptography_flutter (0.2.0): + - Flutter - device_info_plus (0.0.1): - Flutter - Firebase/Auth (11.4.0): @@ -261,6 +263,7 @@ DEPENDENCIES: - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) - cloud_functions (from `.symlinks/plugins/cloud_functions/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`) + - cryptography_flutter (from `.symlinks/plugins/cryptography_flutter/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) @@ -337,6 +340,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/cloud_functions/ios" connectivity_plus: :path: ".symlinks/plugins/connectivity_plus/darwin" + cryptography_flutter: + :path: ".symlinks/plugins/cryptography_flutter/ios" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" firebase_auth: @@ -402,6 +407,7 @@ SPEC CHECKSUMS: cloud_firestore: 8794ea2885e367f0a2096338964ddfd49739b2c7 cloud_functions: d1dc9179c2db1729cb9bd0c9683909216a0f2230 connectivity_plus: 4c41c08fc6d7c91f63bc7aec70ffe3730b04f563 + cryptography_flutter: 381bdacc984abcfbe3ca45ef7c76566ff061614c device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 Firebase: cf1b19f21410b029b6786a54e9764a0cacad3c99 firebase_auth: 42718683069d35d73af7a986b55b194589039e5e diff --git a/app/lib/ui/flow/auth/sign_in_method_screen.dart b/app/lib/ui/flow/auth/sign_in_method_screen.dart index ce148195..74588e74 100644 --- a/app/lib/ui/flow/auth/sign_in_method_screen.dart +++ b/app/lib/ui/flow/auth/sign_in_method_screen.dart @@ -108,21 +108,17 @@ class _SignInMethodScreenState extends ConsumerState { final state = ref.watch(signInMethodsStateProvider); final user = ref.read(currentUserPod); - if (mounted && (user?.first_name == null || user!.first_name!.isEmpty)) { - PickNameRoute(user!).go(context); - } - - if (state.isNewUser && mounted) { - ConnectionRoute().go(context); - } else { - navigateToHome(); + if (mounted) { + if ((user?.first_name == null || user!.first_name!.isEmpty)) { + const PickNameRoute().go(context); + } else if (state.isNewUser && mounted) { + ConnectionRoute().go(context); + } else { + HomeRoute().go(context); + } } } - void navigateToHome() { - if (mounted) HomeRoute().go(context); - } - void _listenSignInSuccess() { ref.listen( signInMethodsStateProvider.select((value) => value.socialSignInCompleted), diff --git a/app/lib/ui/flow/home/home_screen_viewmodel.dart b/app/lib/ui/flow/home/home_screen_viewmodel.dart index 026b189b..bf892e2f 100644 --- a/app/lib/ui/flow/home/home_screen_viewmodel.dart +++ b/app/lib/ui/flow/home/home_screen_viewmodel.dart @@ -33,6 +33,7 @@ final homeViewStateProvider = ref.read(currentUserPod), ref.read(apiUserServiceProvider), ref.read(currentUserSessionPod), + ref.read(authServiceProvider) ); ref.listen(currentUserPod, (prev, user) { notifier._onUpdateUser(prevUser: prev, currentUser: user); @@ -54,6 +55,7 @@ class HomeViewNotifier extends StateNotifier { ApiUser? _currentUser; final ApiUserService userService; final ApiSession? _userSession; + final AuthService authService; HomeViewNotifier( this.spaceService, @@ -64,13 +66,15 @@ class HomeViewNotifier extends StateNotifier { this._currentUser, this.userService, this._userSession, + this.authService, ) : super(const HomeViewState()) { - updateUser(); + _listenUser(); fetchData(); _listenPlaces(); } StreamSubscription>? _spacesSubscription; + StreamSubscription? _userSubscription; StreamSubscription? _userSessionSubscription; StreamSubscription?>? _spacePlacesSubscription; @@ -86,18 +90,18 @@ class HomeViewNotifier extends StateNotifier { listenUserSession(); } - void updateUser() async { + void _listenUser() async { if (_currentUser == null) return; - try { - final user = await userService.getUser(_currentUser!.id); - if (user != null) { - _currentUser = user; - userService.updateUser(user); + + _userSubscription?.cancel(); + _userSubscription = + userService.getUserStream(_currentUser!.id).listen((user) { + if (_currentUser != user) { + authService.saveUser(user); } - } catch (error) { - logger.e( - 'HomeScreenViewModel: error while updating user ${_currentUser?.id}'); - } + }, onError: (error) { + logger.e('HomeScreenViewModel: error while get user $error'); + }); } void _listenPlaces() async { @@ -148,6 +152,7 @@ class HomeViewNotifier extends StateNotifier { } void _cancelSubscriptions() { + _userSubscription?.cancel(); _spacePlacesSubscription?.cancel(); _spacesSubscription?.cancel(); _userSessionSubscription?.cancel(); @@ -200,7 +205,6 @@ class HomeViewNotifier extends StateNotifier { await userService.updateCurrentUserState(userState, battery_pct: batterLevel); - } catch (error, stack) { logger.e( 'HomeViewNotifier: error while update current user state', @@ -210,8 +214,6 @@ class HomeViewNotifier extends StateNotifier { } } - - Future checkUserState(ConnectivityResult result) async { final isLocationEnabled = await permissionService.isLocationAlwaysEnabled(); final isConnected = result == ConnectivityResult.mobile || diff --git a/app/lib/ui/flow/journey/detail/user_journey_detail_screen.dart b/app/lib/ui/flow/journey/detail/user_journey_detail_screen.dart index 94873a20..7e487d8b 100644 --- a/app/lib/ui/flow/journey/detail/user_journey_detail_screen.dart +++ b/app/lib/ui/flow/journey/detail/user_journey_detail_screen.dart @@ -113,7 +113,7 @@ class _UserJourneyDetailScreenState state.journey!.isSteady(), ), if (state.journey!.isMoving()) - _journeyPlacesInfo(state.addressTo, state.journey!.update_at, true), + _journeyPlacesInfo(state.addressTo, state.journey!.updated_at, true), ], ), ); diff --git a/app/lib/ui/flow/journey/timeline/journey_timeline_screen.dart b/app/lib/ui/flow/journey/timeline/journey_timeline_screen.dart index 058d53ae..1460349f 100644 --- a/app/lib/ui/flow/journey/timeline/journey_timeline_screen.dart +++ b/app/lib/ui/flow/journey/timeline/journey_timeline_screen.dart @@ -223,9 +223,9 @@ class _JourneyTimelineScreenState extends ConsumerState { ) { final location = LatLng(journey.from_latitude, journey.from_longitude); final steadyDuration = - notifier.getSteadyDuration(journey.created_at!, journey.update_at!); - final formattedTime = _getFormattedJourneyTime( - journey.created_at ?? 0, journey.update_at ?? 0); + notifier.getSteadyDuration(journey.created_at, journey.updated_at); + final formattedTime = + _getFormattedJourneyTime(journey.created_at, journey.updated_at); return Padding( padding: EdgeInsets.only(top: isFirstItem ? 16 : 0), @@ -273,8 +273,8 @@ class _JourneyTimelineScreenState extends ConsumerState { bool isLastItem, String mapType, ) { - final time = _getFormattedJourneyTime( - journey.created_at ?? 0, journey.update_at ?? 0); + final time = + _getFormattedJourneyTime(journey.created_at, journey.updated_at); final distance = notifier.getDistanceString(journey.route_distance ?? 0); final fromLatLng = LatLng(journey.from_latitude, journey.from_longitude); final toLatLng = diff --git a/app/lib/ui/flow/journey/timeline/journey_timeline_view_model.dart b/app/lib/ui/flow/journey/timeline/journey_timeline_view_model.dart index 3a6cef69..79e6a46e 100644 --- a/app/lib/ui/flow/journey/timeline/journey_timeline_view_model.dart +++ b/app/lib/ui/flow/journey/timeline/journey_timeline_view_model.dart @@ -79,8 +79,8 @@ class JourneyTimelineViewModel extends StateNotifier { // Filter by date range final filteredJourneys = journeys.where((journey) { - return journey.created_at! >= from && journey.created_at! <= to || - (journey.update_at! >= from && journey.update_at! <= to); + return journey.created_at >= from && journey.created_at <= to || + (journey.updated_at >= from && journey.updated_at <= to); }).toList(); // Combine all journeys and sort @@ -108,13 +108,13 @@ class JourneyTimelineViewModel extends StateNotifier { if (allJourneys.isEmpty) return null; int earliestTimestamp = allJourneys .map((journey) => journey.created_at) - .fold(allJourneys.first.created_at!, (a, b) => a < b! ? a : b); + .fold(allJourneys.first.created_at, (a, b) => a < b ? a : b); return earliestTimestamp; } List _sortJourneysByUpdateAt( List journeys) { - journeys.sort((a, b) => (b.update_at ?? 0).compareTo(a.update_at ?? 0)); + journeys.sort((a, b) => b.updated_at.compareTo(a.updated_at)); return journeys; } diff --git a/app/lib/ui/flow/navigation/routes.dart b/app/lib/ui/flow/navigation/routes.dart index 359d6b38..21a8340e 100644 --- a/app/lib/ui/flow/navigation/routes.dart +++ b/app/lib/ui/flow/navigation/routes.dart @@ -42,9 +42,10 @@ final goRouterProvider = FutureProvider((ref) async { final isIntroScreenShown = ref.read(isIntroScreenShownPod); final user = ref.read(currentUserPod); + print("XXX user $user"); if (!isIntroScreenShown) return IntroRoute().location; if (user == null) return SignInMethodRoute().location; - if (user.first_name?.isEmpty ?? true) return PickNameRoute(user).location; + if (user.first_name?.isEmpty ?? true) return const PickNameRoute().location; return HomeRoute().location; } @@ -86,15 +87,11 @@ class SignInMethodRoute extends GoRouteData { path: '/pick-name', ) class PickNameRoute extends GoRouteData { - final ApiUser $extra; - - const PickNameRoute(this.$extra); + const PickNameRoute(); @override Widget build(BuildContext context, GoRouterState state) { - return PickNameScreen( - user: $extra, - ); + return const PickNameScreen(); } } diff --git a/app/lib/ui/flow/navigation/routes.g.dart b/app/lib/ui/flow/navigation/routes.g.dart index 8689374f..df08c1b2 100644 --- a/app/lib/ui/flow/navigation/routes.g.dart +++ b/app/lib/ui/flow/navigation/routes.g.dart @@ -71,24 +71,20 @@ RouteBase get $pickNameRoute => GoRouteData.$route( ); extension $PickNameRouteExtension on PickNameRoute { - static PickNameRoute _fromState(GoRouterState state) => PickNameRoute( - state.extra as ApiUser, - ); + static PickNameRoute _fromState(GoRouterState state) => const PickNameRoute(); String get location => GoRouteData.$location( '/pick-name', ); - void go(BuildContext context) => context.go(location, extra: $extra); + void go(BuildContext context) => context.go(location); - Future push(BuildContext context) => - context.push(location, extra: $extra); + Future push(BuildContext context) => context.push(location); void pushReplacement(BuildContext context) => - context.pushReplacement(location, extra: $extra); + context.pushReplacement(location); - void replace(BuildContext context) => - context.replace(location, extra: $extra); + void replace(BuildContext context) => context.replace(location); } RouteBase get $connectionRoute => GoRouteData.$route( diff --git a/app/lib/ui/flow/onboard/pick_name_screen.dart b/app/lib/ui/flow/onboard/pick_name_screen.dart index 34af5566..adf55d82 100644 --- a/app/lib/ui/flow/onboard/pick_name_screen.dart +++ b/app/lib/ui/flow/onboard/pick_name_screen.dart @@ -1,4 +1,3 @@ -import 'package:data/api/auth/auth_models.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:style/button/bottom_sticky_overlay.dart'; @@ -16,9 +15,7 @@ import 'package:yourspace_flutter/ui/flow/onboard/pick_name_view_model.dart'; import '../../components/no_internet_screen.dart'; class PickNameScreen extends ConsumerStatefulWidget { - final ApiUser? user; - - const PickNameScreen({super.key, this.user}); + const PickNameScreen({super.key}); @override ConsumerState createState() => _PickNameScreenState(); @@ -68,7 +65,7 @@ class _PickNameScreenState extends ConsumerState { enabled: state.enableBtn, progress: state.savingUser, onPressed: () { - _checkInternet(widget.user ?? state.user); + _checkInternet(); }, ), ) @@ -113,9 +110,9 @@ class _PickNameScreenState extends ConsumerState { }); } - void _checkInternet(ApiUser user) async { + void _checkInternet() async { final isNetworkOff = await checkInternetConnectivity(); - isNetworkOff ? _showSnackBar() : _notifier.saveUser(user); + isNetworkOff ? _showSnackBar() : _notifier.saveUser(); } void _showSnackBar() { diff --git a/app/lib/ui/flow/onboard/pick_name_view_model.dart b/app/lib/ui/flow/onboard/pick_name_view_model.dart index 17e0c5fc..556f6454 100644 --- a/app/lib/ui/flow/onboard/pick_name_view_model.dart +++ b/app/lib/ui/flow/onboard/pick_name_view_model.dart @@ -8,11 +8,12 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'pick_name_view_model.freezed.dart'; -final pickNameStateNotifierProvider = StateNotifierProvider.autoDispose< - PickNameStateNotifier, PickNameState>((ref) { +final pickNameStateNotifierProvider = + StateNotifierProvider.autoDispose( + (ref) { return PickNameStateNotifier( - ref.watch(authServiceProvider), - ref.watch(currentUserPod), + ref.read(authServiceProvider), + ref.read(currentUserPod), ); }); @@ -21,17 +22,24 @@ class PickNameStateNotifier extends StateNotifier { final ApiUser? user; PickNameStateNotifier(this._authService, this.user) - : super(PickNameState(firstName: TextEditingController(), lastName: TextEditingController(), user: user!)); + : super(PickNameState( + firstName: TextEditingController(), + lastName: TextEditingController())); void enableNextButton() { - state = state.copyWith(enableBtn: state.firstName.text.isNotEmpty && state.firstName.text.length >= 3); + state = state.copyWith( + enableBtn: state.firstName.text.isNotEmpty && + state.firstName.text.length >= 3); } - Future saveUser(ApiUser user) async { + Future saveUser() async { try { + if (user == null) return; state = state.copyWith(savingUser: true, error: null); - final newUser = user.copyWith(first_name: state.firstName.text, last_name: state.lastName.text); - _authService.updateCurrentUser(newUser); + final firstName = state.firstName.text; + final lastName = state.lastName.text; + + _authService.updateUserName(firstName: firstName, lastName: lastName); state = state.copyWith(savingUser: false, saved: true, error: null); } catch (error, stack) { state = state.copyWith(savingUser: false, error: error); @@ -42,6 +50,13 @@ class PickNameStateNotifier extends StateNotifier { ); } } + + @override + void dispose() { + state.firstName.dispose(); + state.lastName.dispose(); + super.dispose(); + } } @freezed @@ -53,6 +68,5 @@ class PickNameState with _$PickNameState { Object? error, required TextEditingController firstName, required TextEditingController lastName, - required ApiUser user, }) = _PickNameState; } diff --git a/app/lib/ui/flow/onboard/pick_name_view_model.freezed.dart b/app/lib/ui/flow/onboard/pick_name_view_model.freezed.dart index f0444eb4..2342f712 100644 --- a/app/lib/ui/flow/onboard/pick_name_view_model.freezed.dart +++ b/app/lib/ui/flow/onboard/pick_name_view_model.freezed.dart @@ -22,7 +22,6 @@ mixin _$PickNameState { Object? get error => throw _privateConstructorUsedError; TextEditingController get firstName => throw _privateConstructorUsedError; TextEditingController get lastName => throw _privateConstructorUsedError; - ApiUser get user => throw _privateConstructorUsedError; @JsonKey(ignore: true) $PickNameStateCopyWith get copyWith => @@ -41,10 +40,7 @@ abstract class $PickNameStateCopyWith<$Res> { bool saved, Object? error, TextEditingController firstName, - TextEditingController lastName, - ApiUser user}); - - $ApiUserCopyWith<$Res> get user; + TextEditingController lastName}); } /// @nodoc @@ -66,7 +62,6 @@ class _$PickNameStateCopyWithImpl<$Res, $Val extends PickNameState> Object? error = freezed, Object? firstName = null, Object? lastName = null, - Object? user = null, }) { return _then(_value.copyWith( enableBtn: null == enableBtn @@ -90,20 +85,8 @@ class _$PickNameStateCopyWithImpl<$Res, $Val extends PickNameState> ? _value.lastName : lastName // ignore: cast_nullable_to_non_nullable as TextEditingController, - user: null == user - ? _value.user - : user // ignore: cast_nullable_to_non_nullable - as ApiUser, ) as $Val); } - - @override - @pragma('vm:prefer-inline') - $ApiUserCopyWith<$Res> get user { - return $ApiUserCopyWith<$Res>(_value.user, (value) { - return _then(_value.copyWith(user: value) as $Val); - }); - } } /// @nodoc @@ -120,11 +103,7 @@ abstract class _$$PickNameStateImplCopyWith<$Res> bool saved, Object? error, TextEditingController firstName, - TextEditingController lastName, - ApiUser user}); - - @override - $ApiUserCopyWith<$Res> get user; + TextEditingController lastName}); } /// @nodoc @@ -144,7 +123,6 @@ class __$$PickNameStateImplCopyWithImpl<$Res> Object? error = freezed, Object? firstName = null, Object? lastName = null, - Object? user = null, }) { return _then(_$PickNameStateImpl( enableBtn: null == enableBtn @@ -168,10 +146,6 @@ class __$$PickNameStateImplCopyWithImpl<$Res> ? _value.lastName : lastName // ignore: cast_nullable_to_non_nullable as TextEditingController, - user: null == user - ? _value.user - : user // ignore: cast_nullable_to_non_nullable - as ApiUser, )); } } @@ -185,8 +159,7 @@ class _$PickNameStateImpl implements _PickNameState { this.saved = false, this.error, required this.firstName, - required this.lastName, - required this.user}); + required this.lastName}); @override @JsonKey() @@ -203,12 +176,10 @@ class _$PickNameStateImpl implements _PickNameState { final TextEditingController firstName; @override final TextEditingController lastName; - @override - final ApiUser user; @override String toString() { - return 'PickNameState(enableBtn: $enableBtn, savingUser: $savingUser, saved: $saved, error: $error, firstName: $firstName, lastName: $lastName, user: $user)'; + return 'PickNameState(enableBtn: $enableBtn, savingUser: $savingUser, saved: $saved, error: $error, firstName: $firstName, lastName: $lastName)'; } @override @@ -225,13 +196,12 @@ class _$PickNameStateImpl implements _PickNameState { (identical(other.firstName, firstName) || other.firstName == firstName) && (identical(other.lastName, lastName) || - other.lastName == lastName) && - (identical(other.user, user) || other.user == user)); + other.lastName == lastName)); } @override int get hashCode => Object.hash(runtimeType, enableBtn, savingUser, saved, - const DeepCollectionEquality().hash(error), firstName, lastName, user); + const DeepCollectionEquality().hash(error), firstName, lastName); @JsonKey(ignore: true) @override @@ -247,8 +217,7 @@ abstract class _PickNameState implements PickNameState { final bool saved, final Object? error, required final TextEditingController firstName, - required final TextEditingController lastName, - required final ApiUser user}) = _$PickNameStateImpl; + required final TextEditingController lastName}) = _$PickNameStateImpl; @override bool get enableBtn; @@ -263,8 +232,6 @@ abstract class _PickNameState implements PickNameState { @override TextEditingController get lastName; @override - ApiUser get user; - @override @JsonKey(ignore: true) _$$PickNameStateImplCopyWith<_$PickNameStateImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/app/lib/ui/flow/space/create/create_space_view_model.dart b/app/lib/ui/flow/space/create/create_space_view_model.dart index 3273592b..9ac329d5 100644 --- a/app/lib/ui/flow/space/create/create_space_view_model.dart +++ b/app/lib/ui/flow/space/create/create_space_view_model.dart @@ -1,5 +1,7 @@ +import 'package:data/api/auth/auth_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/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -9,23 +11,26 @@ part 'create_space_view_model.freezed.dart'; final createSpaceViewStateProvider = StateNotifierProvider.autoDispose< CreateSpaceViewNotifier, CreateSpaceViewState>((ref) { return CreateSpaceViewNotifier( - ref.read(spaceServiceProvider), - ); + ref.read(spaceServiceProvider), ref.read(currentUserPod)); }); class CreateSpaceViewNotifier extends StateNotifier { final SpaceService spaceService; + final ApiUser? currentUser; - CreateSpaceViewNotifier(this.spaceService) + CreateSpaceViewNotifier(this.spaceService, this.currentUser) : super( CreateSpaceViewState(spaceName: TextEditingController()), ); Future createSpace() async { try { + if (currentUser == null) return; state = state.copyWith(isCreating: true, invitationCode: '', error: null); - final invitationCode = - await spaceService.createSpaceAndGetInviteCode(state.spaceName.text); + final invitationCode = await spaceService.createSpaceAndGetInviteCode( + spaceName: state.spaceName.text, + userId: currentUser!.id, + identityKeyPublic: currentUser!.identity_key_public); state = state.copyWith(isCreating: false, invitationCode: invitationCode); } catch (error, stack) { state = state.copyWith(error: error, isCreating: false); diff --git a/app/lib/ui/flow/space/join/join_space_view_model.dart b/app/lib/ui/flow/space/join/join_space_view_model.dart index 7880d95b..a83b3738 100644 --- a/app/lib/ui/flow/space/join/join_space_view_model.dart +++ b/app/lib/ui/flow/space/join/join_space_view_model.dart @@ -88,7 +88,7 @@ class JoinSpaceViewNotifier extends StateNotifier { try { if (state.space == null || _currentUser == null) return; state = state.copyWith(verifying: true, error: null); - await spaceService.joinSpace(state.space?.id ?? '', _currentUser.id); + await spaceService.joinSpace(state.space?.id ?? ''); state = state.copyWith(verifying: false, spaceJoined: true, error: null); } catch (error, stack) { state = state.copyWith(error: error, verifying: false); diff --git a/app/pubspec.lock b/app/pubspec.lock index 84ccc971..23e0a0e1 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -17,6 +17,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.46" + adaptive_number: + dependency: transitive + description: + name: adaptive_number + sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" + url: "https://pub.dev" + source: hosted + version: "1.0.0" analyzer: dependency: transitive description: @@ -321,6 +329,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.6" + cryptography: + dependency: transitive + description: + name: cryptography + sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + cryptography_flutter: + dependency: transitive + description: + name: cryptography_flutter + sha256: a7fc3f0de42fb0947cbf213257aa3a69c89df561d104723ede8050658621f292 + url: "https://pub.dev" + source: hosted + version: "2.3.2" csslib: dependency: transitive description: @@ -408,6 +432,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + ed25519_edwards: + dependency: transitive + description: + name: ed25519_edwards + sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd" + url: "https://pub.dev" + source: hosted + version: "0.3.1" fake_async: dependency: transitive description: @@ -1153,10 +1185,10 @@ packages: dependency: transitive description: name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.7.1" + version: "0.6.7" json_annotation: dependency: "direct main" description: @@ -1197,6 +1229,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + libsignal_protocol_dart: + dependency: transitive + description: + name: libsignal_protocol_dart + sha256: "2a8d54cddb89eab0301d333c4346d7edc920da0a0c0daa5e324878de2841dce6" + url: "https://pub.dev" + source: hosted + version: "0.7.1" lints: dependency: transitive description: @@ -1269,6 +1309,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + optional: + dependency: transitive + description: + name: optional + sha256: f80327d7a3335a0be68418072668043c7ab291df575c21aa42e0c5633641da39 + url: "https://pub.dev" + source: hosted + version: "6.1.0+1" package_config: dependency: transitive description: @@ -1429,6 +1477,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" + url: "https://pub.dev" + source: hosted + version: "3.9.1" pool: dependency: transitive description: @@ -1437,6 +1493,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + protobuf: + dependency: transitive + description: + name: protobuf + sha256: "01dd9bd0fa02548bf2ceee13545d4a0ec6046459d847b6b061d8a27237108a08" + url: "https://pub.dev" + source: hosted + version: "2.1.0" pub_semver: dependency: transitive description: @@ -1881,6 +1945,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + very_good_analysis: + dependency: transitive + description: + name: very_good_analysis + sha256: "9ae7f3a3bd5764fb021b335ca28a34f040cd0ab6eec00a1b213b445dae58a4b8" + url: "https://pub.dev" + source: hosted + version: "5.1.0" visibility_detector: dependency: "direct main" description: @@ -1945,6 +2017,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.5" + x25519: + dependency: transitive + description: + name: x25519 + sha256: cec3c125f0d934dccba6c4cab48f3fbf866dc78895dcc5a1584d35b0a845005b + url: "https://pub.dev" + source: hosted + version: "0.1.1" xdg_directories: dependency: transitive description: diff --git a/data/lib/api/auth/api_user_service.dart b/data/lib/api/auth/api_user_service.dart index c41f13c9..baed74d7 100644 --- a/data/lib/api/auth/api_user_service.dart +++ b/data/lib/api/auth/api_user_service.dart @@ -12,15 +12,15 @@ import '../../storage/app_preferences.dart'; import 'auth_models.dart'; final apiUserServiceProvider = StateProvider((ref) => ApiUserService( - ref.read(firestoreProvider), - ref.read(deviceServiceProvider), - ref.read(currentUserJsonPod.notifier), - ref.read(currentSpaceId.notifier), - ref.read(currentUserSessionJsonPod.notifier), - ref.read(isOnboardingShownPod.notifier), - ref.read(currentUserPod), - ref.read(locationManagerProvider), - )); + ref.read(firestoreProvider), + ref.read(deviceServiceProvider), + ref.read(currentUserJsonPod.notifier), + ref.read(currentSpaceId.notifier), + ref.read(currentUserSessionJsonPod.notifier), + ref.read(isOnboardingShownPod.notifier), + ref.read(currentUserPod), + ref.read(locationManagerProvider), + ref.read(userPassKeyPod.notifier))); class ApiUserService { final FirebaseFirestore _db; @@ -29,19 +29,20 @@ class ApiUserService { final StateController currentUserSpaceId; final StateController userSessionJsonNotifier; final StateController onBoardNotifier; + final StateController userPassKeyNotifier; ApiUser? currentUser; final LocationManager locationManager; ApiUserService( - this._db, - this._device, - this.userJsonNotifier, - this.currentUserSpaceId, - this.userSessionJsonNotifier, - this.onBoardNotifier, - this.currentUser, - this.locationManager, - ); + this._db, + this._device, + this.userJsonNotifier, + this.currentUserSpaceId, + this.userSessionJsonNotifier, + this.onBoardNotifier, + this.currentUser, + this.locationManager, + this.userPassKeyNotifier); CollectionReference get _userRef => _db.collection("users").withConverter( @@ -107,7 +108,6 @@ class ApiUserService { created_at: DateTime.now().millisecondsSinceEpoch, ); await sessionDocRef.set(session); - // await _locationService.saveLastKnownLocation(uid); return {'isNewUser': true, 'user': user, 'session': session}; } } @@ -116,7 +116,7 @@ class ApiUserService { if (userId == null) return null; var snapshot = await _userRef.doc(userId).get(); if (snapshot.exists) { - return snapshot.data() as ApiUser; + return snapshot.data(); } return null; } @@ -161,6 +161,14 @@ class ApiUserService { await _userRef.doc(user.id).set(user); } + Future updateUserName(String userId, + {required String firstName, String? lastName}) async { + await _userRef.doc(userId).update({ + "first_name": firstName, + "last_name": lastName, + }); + } + Future deleteUser(String userId) async { await _db.collection("users").doc(userId).delete(); } @@ -284,5 +292,15 @@ class ApiUserService { userSessionJsonNotifier.state = null; onBoardNotifier.state = false; currentUserSpaceId.state = null; + userPassKeyNotifier.state = null; + } + + Future updateKeys( + String id, Blob publicKey, Blob privateKey, Blob saltBlob) async { + await _userRef.doc(id).update({ + "identity_key_public": publicKey, + "identity_key_private": privateKey, + "identity_key_salt": saltBlob, + }); } } diff --git a/data/lib/api/auth/auth_models.dart b/data/lib/api/auth/auth_models.dart index bf6ed4e2..fc557d29 100644 --- a/data/lib/api/auth/auth_models.dart +++ b/data/lib/api/auth/auth_models.dart @@ -5,8 +5,10 @@ import 'dart:convert'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/location/location.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import '../../converter/blob_converter.dart'; part 'auth_models.freezed.dart'; + part 'auth_models.g.dart'; const LOGIN_TYPE_GOOGLE = 1; @@ -31,6 +33,9 @@ class ApiUser with _$ApiUser { @Default([]) List? space_ids, int? battery_pct, @Default("") String? fcm_token, + @BlobConverter() Blob? identity_key_public, + @BlobConverter() Blob? identity_key_private, + @BlobConverter() Blob? identity_key_salt, int? state, int? created_at, int? updated_at, diff --git a/data/lib/api/auth/auth_models.freezed.dart b/data/lib/api/auth/auth_models.freezed.dart index 3680f418..3d3923a4 100644 --- a/data/lib/api/auth/auth_models.freezed.dart +++ b/data/lib/api/auth/auth_models.freezed.dart @@ -31,12 +31,22 @@ mixin _$ApiUser { List? get space_ids => throw _privateConstructorUsedError; int? get battery_pct => throw _privateConstructorUsedError; String? get fcm_token => throw _privateConstructorUsedError; + @BlobConverter() + Blob? get identity_key_public => throw _privateConstructorUsedError; + @BlobConverter() + Blob? get identity_key_private => throw _privateConstructorUsedError; + @BlobConverter() + Blob? get identity_key_salt => throw _privateConstructorUsedError; int? get state => throw _privateConstructorUsedError; int? get created_at => throw _privateConstructorUsedError; int? get updated_at => throw _privateConstructorUsedError; + /// Serializes this ApiUser to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiUser + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiUserCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -57,6 +67,9 @@ abstract class $ApiUserCopyWith<$Res> { List? space_ids, int? battery_pct, String? fcm_token, + @BlobConverter() Blob? identity_key_public, + @BlobConverter() Blob? identity_key_private, + @BlobConverter() Blob? identity_key_salt, int? state, int? created_at, int? updated_at}); @@ -72,6 +85,8 @@ class _$ApiUserCopyWithImpl<$Res, $Val extends ApiUser> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiUser + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -86,6 +101,9 @@ class _$ApiUserCopyWithImpl<$Res, $Val extends ApiUser> Object? space_ids = freezed, Object? battery_pct = freezed, Object? fcm_token = freezed, + Object? identity_key_public = freezed, + Object? identity_key_private = freezed, + Object? identity_key_salt = freezed, Object? state = freezed, Object? created_at = freezed, Object? updated_at = freezed, @@ -135,6 +153,18 @@ class _$ApiUserCopyWithImpl<$Res, $Val extends ApiUser> ? _value.fcm_token : fcm_token // ignore: cast_nullable_to_non_nullable as String?, + identity_key_public: freezed == identity_key_public + ? _value.identity_key_public + : identity_key_public // ignore: cast_nullable_to_non_nullable + as Blob?, + identity_key_private: freezed == identity_key_private + ? _value.identity_key_private + : identity_key_private // ignore: cast_nullable_to_non_nullable + as Blob?, + identity_key_salt: freezed == identity_key_salt + ? _value.identity_key_salt + : identity_key_salt // ignore: cast_nullable_to_non_nullable + as Blob?, state: freezed == state ? _value.state : state // ignore: cast_nullable_to_non_nullable @@ -170,6 +200,9 @@ abstract class _$$ApiUserImplCopyWith<$Res> implements $ApiUserCopyWith<$Res> { List? space_ids, int? battery_pct, String? fcm_token, + @BlobConverter() Blob? identity_key_public, + @BlobConverter() Blob? identity_key_private, + @BlobConverter() Blob? identity_key_salt, int? state, int? created_at, int? updated_at}); @@ -183,6 +216,8 @@ class __$$ApiUserImplCopyWithImpl<$Res> _$ApiUserImpl _value, $Res Function(_$ApiUserImpl) _then) : super(_value, _then); + /// Create a copy of ApiUser + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -197,6 +232,9 @@ class __$$ApiUserImplCopyWithImpl<$Res> Object? space_ids = freezed, Object? battery_pct = freezed, Object? fcm_token = freezed, + Object? identity_key_public = freezed, + Object? identity_key_private = freezed, + Object? identity_key_salt = freezed, Object? state = freezed, Object? created_at = freezed, Object? updated_at = freezed, @@ -246,6 +284,18 @@ class __$$ApiUserImplCopyWithImpl<$Res> ? _value.fcm_token : fcm_token // ignore: cast_nullable_to_non_nullable as String?, + identity_key_public: freezed == identity_key_public + ? _value.identity_key_public + : identity_key_public // ignore: cast_nullable_to_non_nullable + as Blob?, + identity_key_private: freezed == identity_key_private + ? _value.identity_key_private + : identity_key_private // ignore: cast_nullable_to_non_nullable + as Blob?, + identity_key_salt: freezed == identity_key_salt + ? _value.identity_key_salt + : identity_key_salt // ignore: cast_nullable_to_non_nullable + as Blob?, state: freezed == state ? _value.state : state // ignore: cast_nullable_to_non_nullable @@ -277,6 +327,9 @@ class _$ApiUserImpl extends _ApiUser { final List? space_ids = const [], this.battery_pct, this.fcm_token = "", + @BlobConverter() this.identity_key_public, + @BlobConverter() this.identity_key_private, + @BlobConverter() this.identity_key_salt, this.state, this.created_at, this.updated_at}) @@ -320,6 +373,15 @@ class _$ApiUserImpl extends _ApiUser { @JsonKey() final String? fcm_token; @override + @BlobConverter() + final Blob? identity_key_public; + @override + @BlobConverter() + final Blob? identity_key_private; + @override + @BlobConverter() + final Blob? identity_key_salt; + @override final int? state; @override final int? created_at; @@ -328,7 +390,7 @@ class _$ApiUserImpl extends _ApiUser { @override String toString() { - return 'ApiUser(id: $id, first_name: $first_name, last_name: $last_name, email: $email, provider_firebase_id_token: $provider_firebase_id_token, auth_type: $auth_type, profile_image: $profile_image, location_enabled: $location_enabled, space_ids: $space_ids, battery_pct: $battery_pct, fcm_token: $fcm_token, state: $state, created_at: $created_at, updated_at: $updated_at)'; + return 'ApiUser(id: $id, first_name: $first_name, last_name: $last_name, email: $email, provider_firebase_id_token: $provider_firebase_id_token, auth_type: $auth_type, profile_image: $profile_image, location_enabled: $location_enabled, space_ids: $space_ids, battery_pct: $battery_pct, fcm_token: $fcm_token, identity_key_public: $identity_key_public, identity_key_private: $identity_key_private, identity_key_salt: $identity_key_salt, state: $state, created_at: $created_at, updated_at: $updated_at)'; } @override @@ -358,6 +420,12 @@ class _$ApiUserImpl extends _ApiUser { other.battery_pct == battery_pct) && (identical(other.fcm_token, fcm_token) || other.fcm_token == fcm_token) && + (identical(other.identity_key_public, identity_key_public) || + other.identity_key_public == identity_key_public) && + (identical(other.identity_key_private, identity_key_private) || + other.identity_key_private == identity_key_private) && + (identical(other.identity_key_salt, identity_key_salt) || + other.identity_key_salt == identity_key_salt) && (identical(other.state, state) || other.state == state) && (identical(other.created_at, created_at) || other.created_at == created_at) && @@ -365,7 +433,7 @@ class _$ApiUserImpl extends _ApiUser { other.updated_at == updated_at)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -380,11 +448,16 @@ class _$ApiUserImpl extends _ApiUser { const DeepCollectionEquality().hash(_space_ids), battery_pct, fcm_token, + identity_key_public, + identity_key_private, + identity_key_salt, state, created_at, updated_at); - @JsonKey(ignore: true) + /// Create a copy of ApiUser + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiUserImplCopyWith<_$ApiUserImpl> get copyWith => @@ -411,6 +484,9 @@ abstract class _ApiUser extends ApiUser { final List? space_ids, final int? battery_pct, final String? fcm_token, + @BlobConverter() final Blob? identity_key_public, + @BlobConverter() final Blob? identity_key_private, + @BlobConverter() final Blob? identity_key_salt, final int? state, final int? created_at, final int? updated_at}) = _$ApiUserImpl; @@ -441,13 +517,25 @@ abstract class _ApiUser extends ApiUser { @override String? get fcm_token; @override + @BlobConverter() + Blob? get identity_key_public; + @override + @BlobConverter() + Blob? get identity_key_private; + @override + @BlobConverter() + Blob? get identity_key_salt; + @override int? get state; @override int? get created_at; @override int? get updated_at; + + /// Create a copy of ApiUser + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiUserImplCopyWith<_$ApiUserImpl> get copyWith => throw _privateConstructorUsedError; } @@ -467,8 +555,12 @@ mixin _$ApiSession { int? get created_at => throw _privateConstructorUsedError; int? get app_version => throw _privateConstructorUsedError; + /// Serializes this ApiSession to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiSession + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiSessionCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -500,6 +592,8 @@ class _$ApiSessionCopyWithImpl<$Res, $Val extends ApiSession> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiSession + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -576,6 +670,8 @@ class __$$ApiSessionImplCopyWithImpl<$Res> _$ApiSessionImpl _value, $Res Function(_$ApiSessionImpl) _then) : super(_value, _then); + /// Create a copy of ApiSession + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -686,12 +782,14 @@ class _$ApiSessionImpl extends _ApiSession { other.app_version == app_version)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash(runtimeType, id, user_id, platform, session_active, device_name, device_id, created_at, app_version); - @JsonKey(ignore: true) + /// Create a copy of ApiSession + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiSessionImplCopyWith<_$ApiSessionImpl> get copyWith => @@ -736,8 +834,11 @@ abstract class _ApiSession extends ApiSession { int? get created_at; @override int? get app_version; + + /// Create a copy of ApiSession + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiSessionImplCopyWith<_$ApiSessionImpl> get copyWith => throw _privateConstructorUsedError; } @@ -753,8 +854,12 @@ mixin _$ApiUserInfo { bool get isLocationEnabled => throw _privateConstructorUsedError; ApiSession? get session => throw _privateConstructorUsedError; + /// Serializes this ApiUserInfo to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiUserInfo + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiUserInfoCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -786,6 +891,8 @@ class _$ApiUserInfoCopyWithImpl<$Res, $Val extends ApiUserInfo> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiUserInfo + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -814,6 +921,8 @@ class _$ApiUserInfoCopyWithImpl<$Res, $Val extends ApiUserInfo> ) as $Val); } + /// Create a copy of ApiUserInfo + /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') $ApiUserCopyWith<$Res> get user { @@ -822,6 +931,8 @@ class _$ApiUserInfoCopyWithImpl<$Res, $Val extends ApiUserInfo> }); } + /// Create a copy of ApiUserInfo + /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') $ApiLocationCopyWith<$Res>? get location { @@ -834,6 +945,8 @@ class _$ApiUserInfoCopyWithImpl<$Res, $Val extends ApiUserInfo> }); } + /// Create a copy of ApiUserInfo + /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') $ApiSessionCopyWith<$Res>? get session { @@ -877,6 +990,8 @@ class __$$ApiUserInfoImplCopyWithImpl<$Res> _$ApiUserInfoImpl _value, $Res Function(_$ApiUserInfoImpl) _then) : super(_value, _then); + /// Create a copy of ApiUserInfo + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -946,12 +1061,14 @@ class _$ApiUserInfoImpl extends _ApiUserInfo { (identical(other.session, session) || other.session == session)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash(runtimeType, user, location, isLocationEnabled, session); - @JsonKey(ignore: true) + /// Create a copy of ApiUserInfo + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiUserInfoImplCopyWith<_$ApiUserInfoImpl> get copyWith => @@ -984,8 +1101,11 @@ abstract class _ApiUserInfo extends ApiUserInfo { bool get isLocationEnabled; @override ApiSession? get session; + + /// Create a copy of ApiUserInfo + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiUserInfoImplCopyWith<_$ApiUserInfoImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/data/lib/api/auth/auth_models.g.dart b/data/lib/api/auth/auth_models.g.dart index 435e6543..ea5e1dd1 100644 --- a/data/lib/api/auth/auth_models.g.dart +++ b/data/lib/api/auth/auth_models.g.dart @@ -22,6 +22,12 @@ _$ApiUserImpl _$$ApiUserImplFromJson(Map json) => const [], battery_pct: (json['battery_pct'] as num?)?.toInt(), fcm_token: json['fcm_token'] as String? ?? "", + identity_key_public: + const BlobConverter().fromJson(json['identity_key_public']), + identity_key_private: + const BlobConverter().fromJson(json['identity_key_private']), + identity_key_salt: + const BlobConverter().fromJson(json['identity_key_salt']), state: (json['state'] as num?)?.toInt(), created_at: (json['created_at'] as num?)?.toInt(), updated_at: (json['updated_at'] as num?)?.toInt(), @@ -40,11 +46,23 @@ Map _$$ApiUserImplToJson(_$ApiUserImpl instance) => 'space_ids': instance.space_ids, 'battery_pct': instance.battery_pct, 'fcm_token': instance.fcm_token, + 'identity_key_public': _$JsonConverterToJson( + instance.identity_key_public, const BlobConverter().toJson), + 'identity_key_private': _$JsonConverterToJson( + instance.identity_key_private, const BlobConverter().toJson), + 'identity_key_salt': _$JsonConverterToJson( + instance.identity_key_salt, const BlobConverter().toJson), 'state': instance.state, 'created_at': instance.created_at, 'updated_at': instance.updated_at, }; +Json? _$JsonConverterToJson( + Value? value, + Json? Function(Value value) toJson, +) => + value == null ? null : toJson(value); + _$ApiSessionImpl _$$ApiSessionImplFromJson(Map json) => _$ApiSessionImpl( id: json['id'] as String, diff --git a/data/lib/api/location/journey/journey.dart b/data/lib/api/location/journey/journey.dart index fd6b0435..6472632a 100644 --- a/data/lib/api/location/journey/journey.dart +++ b/data/lib/api/location/journey/journey.dart @@ -2,10 +2,11 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/location/location.dart'; -import 'package:data/domain/journey_lat_lng_entension.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; +import '../../../converter/blob_converter.dart'; + part 'journey.freezed.dart'; part 'journey.g.dart'; @@ -27,9 +28,9 @@ class ApiLocationJourney with _$ApiLocationJourney { @Default([]) List routes, double? route_distance, int? route_duration, - int? created_at, - int? update_at, - String? type, + required int created_at, + required int updated_at, + required String type, }) = _LocationJourney; factory ApiLocationJourney.fromJson(Map json) => @@ -43,17 +44,11 @@ class ApiLocationJourney with _$ApiLocationJourney { } bool isSteady() { - if (type != null) { - return type == JOURNEY_TYPE_STEADY; - } - return to_latitude == null || to_longitude == null; + return type == JOURNEY_TYPE_STEADY; } bool isMoving() { - if (type != null) { - return type == JOURNEY_TYPE_MOVING; - } - return to_latitude != null && to_longitude != null; + return type == JOURNEY_TYPE_MOVING; } List toRoute() { @@ -61,7 +56,8 @@ class ApiLocationJourney with _$ApiLocationJourney { return []; } else if (isMoving()) { List result = [LatLng(from_latitude, from_longitude)]; - result.addAll(routes.map((route) => route.toLatLng())); + result.addAll( + routes.map((route) => LatLng(route.latitude, route.longitude))); if (to_latitude != null && to_longitude != null) { result.add(LatLng(to_latitude!, to_longitude!)); } @@ -95,3 +91,44 @@ class JourneyRoute with _$JourneyRoute { factory JourneyRoute.fromJson(Map json) => _$JourneyRouteFromJson(json); } + +@freezed +class EncryptedLocationJourney with _$EncryptedLocationJourney { + const EncryptedLocationJourney._(); + + const factory EncryptedLocationJourney({ + String? id, + required String user_id, + @BlobConverter() required Blob from_latitude, + @BlobConverter() required Blob from_longitude, + @BlobConverter() Blob? to_latitude, + @BlobConverter() Blob? to_longitude, + @Default([]) List routes, + double? route_distance, + int? route_duration, + required int created_at, + required int updated_at, + required String type, + }) = _EncryptedLocationJourney; + + factory EncryptedLocationJourney.fromJson(Map json) => + _$EncryptedLocationJourneyFromJson(json); + + factory EncryptedLocationJourney.fromFireStore( + DocumentSnapshot> snapshot, + SnapshotOptions? options) { + Map? data = snapshot.data(); + return EncryptedLocationJourney.fromJson(data!); + } +} + +@freezed +class EncryptedJourneyRoute with _$EncryptedJourneyRoute { + const factory EncryptedJourneyRoute({ + @BlobConverter() required Blob latitude, + @BlobConverter() required Blob longitude, + }) = _EncryptedJourneyRoute; + + factory EncryptedJourneyRoute.fromJson(Map json) => + _$EncryptedJourneyRouteFromJson(json); +} diff --git a/data/lib/api/location/journey/journey.freezed.dart b/data/lib/api/location/journey/journey.freezed.dart index daf77fda..71b1dbc5 100644 --- a/data/lib/api/location/journey/journey.freezed.dart +++ b/data/lib/api/location/journey/journey.freezed.dart @@ -29,12 +29,16 @@ mixin _$ApiLocationJourney { List get routes => throw _privateConstructorUsedError; double? get route_distance => throw _privateConstructorUsedError; int? get route_duration => throw _privateConstructorUsedError; - int? get created_at => throw _privateConstructorUsedError; - int? get update_at => throw _privateConstructorUsedError; - String? get type => throw _privateConstructorUsedError; + int get created_at => throw _privateConstructorUsedError; + int get updated_at => throw _privateConstructorUsedError; + String get type => throw _privateConstructorUsedError; + /// Serializes this ApiLocationJourney to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiLocationJourney + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiLocationJourneyCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -55,9 +59,9 @@ abstract class $ApiLocationJourneyCopyWith<$Res> { List routes, double? route_distance, int? route_duration, - int? created_at, - int? update_at, - String? type}); + int created_at, + int updated_at, + String type}); } /// @nodoc @@ -70,6 +74,8 @@ class _$ApiLocationJourneyCopyWithImpl<$Res, $Val extends ApiLocationJourney> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiLocationJourney + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -82,9 +88,9 @@ class _$ApiLocationJourneyCopyWithImpl<$Res, $Val extends ApiLocationJourney> Object? routes = null, Object? route_distance = freezed, Object? route_duration = freezed, - Object? created_at = freezed, - Object? update_at = freezed, - Object? type = freezed, + Object? created_at = null, + Object? updated_at = null, + Object? type = null, }) { return _then(_value.copyWith( id: freezed == id @@ -123,18 +129,18 @@ class _$ApiLocationJourneyCopyWithImpl<$Res, $Val extends ApiLocationJourney> ? _value.route_duration : route_duration // ignore: cast_nullable_to_non_nullable as int?, - created_at: freezed == created_at + created_at: null == created_at ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable - as int?, - update_at: freezed == update_at - ? _value.update_at - : update_at // ignore: cast_nullable_to_non_nullable - as int?, - type: freezed == type + as int, + updated_at: null == updated_at + ? _value.updated_at + : updated_at // ignore: cast_nullable_to_non_nullable + as int, + type: null == type ? _value.type : type // ignore: cast_nullable_to_non_nullable - as String?, + as String, ) as $Val); } } @@ -157,9 +163,9 @@ abstract class _$$LocationJourneyImplCopyWith<$Res> List routes, double? route_distance, int? route_duration, - int? created_at, - int? update_at, - String? type}); + int created_at, + int updated_at, + String type}); } /// @nodoc @@ -170,6 +176,8 @@ class __$$LocationJourneyImplCopyWithImpl<$Res> _$LocationJourneyImpl _value, $Res Function(_$LocationJourneyImpl) _then) : super(_value, _then); + /// Create a copy of ApiLocationJourney + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -182,9 +190,9 @@ class __$$LocationJourneyImplCopyWithImpl<$Res> Object? routes = null, Object? route_distance = freezed, Object? route_duration = freezed, - Object? created_at = freezed, - Object? update_at = freezed, - Object? type = freezed, + Object? created_at = null, + Object? updated_at = null, + Object? type = null, }) { return _then(_$LocationJourneyImpl( id: freezed == id @@ -223,18 +231,18 @@ class __$$LocationJourneyImplCopyWithImpl<$Res> ? _value.route_duration : route_duration // ignore: cast_nullable_to_non_nullable as int?, - created_at: freezed == created_at + created_at: null == created_at ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable - as int?, - update_at: freezed == update_at - ? _value.update_at - : update_at // ignore: cast_nullable_to_non_nullable - as int?, - type: freezed == type + as int, + updated_at: null == updated_at + ? _value.updated_at + : updated_at // ignore: cast_nullable_to_non_nullable + as int, + type: null == type ? _value.type : type // ignore: cast_nullable_to_non_nullable - as String?, + as String, )); } } @@ -252,9 +260,9 @@ class _$LocationJourneyImpl extends _LocationJourney { final List routes = const [], this.route_distance, this.route_duration, - this.created_at, - this.update_at, - this.type}) + required this.created_at, + required this.updated_at, + required this.type}) : _routes = routes, super._(); @@ -287,15 +295,15 @@ class _$LocationJourneyImpl extends _LocationJourney { @override final int? route_duration; @override - final int? created_at; + final int created_at; @override - final int? update_at; + final int updated_at; @override - final String? type; + final String type; @override String toString() { - return 'ApiLocationJourney(id: $id, user_id: $user_id, from_latitude: $from_latitude, from_longitude: $from_longitude, to_latitude: $to_latitude, to_longitude: $to_longitude, routes: $routes, route_distance: $route_distance, route_duration: $route_duration, created_at: $created_at, update_at: $update_at, type: $type)'; + return 'ApiLocationJourney(id: $id, user_id: $user_id, from_latitude: $from_latitude, from_longitude: $from_longitude, to_latitude: $to_latitude, to_longitude: $to_longitude, routes: $routes, route_distance: $route_distance, route_duration: $route_duration, created_at: $created_at, updated_at: $updated_at, type: $type)'; } @override @@ -320,12 +328,12 @@ class _$LocationJourneyImpl extends _LocationJourney { other.route_duration == route_duration) && (identical(other.created_at, created_at) || other.created_at == created_at) && - (identical(other.update_at, update_at) || - other.update_at == update_at) && + (identical(other.updated_at, updated_at) || + other.updated_at == updated_at) && (identical(other.type, type) || other.type == type)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -339,10 +347,12 @@ class _$LocationJourneyImpl extends _LocationJourney { route_distance, route_duration, created_at, - update_at, + updated_at, type); - @JsonKey(ignore: true) + /// Create a copy of ApiLocationJourney + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$LocationJourneyImplCopyWith<_$LocationJourneyImpl> get copyWith => @@ -368,9 +378,9 @@ abstract class _LocationJourney extends ApiLocationJourney { final List routes, final double? route_distance, final int? route_duration, - final int? created_at, - final int? update_at, - final String? type}) = _$LocationJourneyImpl; + required final int created_at, + required final int updated_at, + required final String type}) = _$LocationJourneyImpl; const _LocationJourney._() : super._(); factory _LocationJourney.fromJson(Map json) = @@ -395,13 +405,16 @@ abstract class _LocationJourney extends ApiLocationJourney { @override int? get route_duration; @override - int? get created_at; + int get created_at; @override - int? get update_at; + int get updated_at; @override - String? get type; + String get type; + + /// Create a copy of ApiLocationJourney + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$LocationJourneyImplCopyWith<_$LocationJourneyImpl> get copyWith => throw _privateConstructorUsedError; } @@ -415,8 +428,12 @@ mixin _$JourneyRoute { double get latitude => throw _privateConstructorUsedError; double get longitude => throw _privateConstructorUsedError; + /// Serializes this JourneyRoute to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of JourneyRoute + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $JourneyRouteCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -440,6 +457,8 @@ class _$JourneyRouteCopyWithImpl<$Res, $Val extends JourneyRoute> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of JourneyRoute + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -478,6 +497,8 @@ class __$$JourneyRouteImplCopyWithImpl<$Res> _$JourneyRouteImpl _value, $Res Function(_$JourneyRouteImpl) _then) : super(_value, _then); + /// Create a copy of JourneyRoute + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -526,11 +547,13 @@ class _$JourneyRouteImpl implements _JourneyRoute { other.longitude == longitude)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash(runtimeType, latitude, longitude); - @JsonKey(ignore: true) + /// Create a copy of JourneyRoute + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$JourneyRouteImplCopyWith<_$JourneyRouteImpl> get copyWith => @@ -556,8 +579,616 @@ abstract class _JourneyRoute implements JourneyRoute { double get latitude; @override double get longitude; + + /// Create a copy of JourneyRoute + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$JourneyRouteImplCopyWith<_$JourneyRouteImpl> get copyWith => throw _privateConstructorUsedError; } + +EncryptedLocationJourney _$EncryptedLocationJourneyFromJson( + Map json) { + return _EncryptedLocationJourney.fromJson(json); +} + +/// @nodoc +mixin _$EncryptedLocationJourney { + String? get id => throw _privateConstructorUsedError; + String get user_id => throw _privateConstructorUsedError; + @BlobConverter() + Blob get from_latitude => throw _privateConstructorUsedError; + @BlobConverter() + Blob get from_longitude => throw _privateConstructorUsedError; + @BlobConverter() + Blob? get to_latitude => throw _privateConstructorUsedError; + @BlobConverter() + Blob? get to_longitude => throw _privateConstructorUsedError; + List get routes => throw _privateConstructorUsedError; + double? get route_distance => throw _privateConstructorUsedError; + int? get route_duration => throw _privateConstructorUsedError; + int get created_at => throw _privateConstructorUsedError; + int get updated_at => throw _privateConstructorUsedError; + String get type => throw _privateConstructorUsedError; + + /// Serializes this EncryptedLocationJourney to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of EncryptedLocationJourney + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $EncryptedLocationJourneyCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $EncryptedLocationJourneyCopyWith<$Res> { + factory $EncryptedLocationJourneyCopyWith(EncryptedLocationJourney value, + $Res Function(EncryptedLocationJourney) then) = + _$EncryptedLocationJourneyCopyWithImpl<$Res, EncryptedLocationJourney>; + @useResult + $Res call( + {String? id, + String user_id, + @BlobConverter() Blob from_latitude, + @BlobConverter() Blob from_longitude, + @BlobConverter() Blob? to_latitude, + @BlobConverter() Blob? to_longitude, + List routes, + double? route_distance, + int? route_duration, + int created_at, + int updated_at, + String type}); +} + +/// @nodoc +class _$EncryptedLocationJourneyCopyWithImpl<$Res, + $Val extends EncryptedLocationJourney> + implements $EncryptedLocationJourneyCopyWith<$Res> { + _$EncryptedLocationJourneyCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of EncryptedLocationJourney + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? user_id = null, + Object? from_latitude = null, + Object? from_longitude = null, + Object? to_latitude = freezed, + Object? to_longitude = freezed, + Object? routes = null, + Object? route_distance = freezed, + Object? route_duration = freezed, + Object? created_at = null, + Object? updated_at = null, + Object? type = null, + }) { + return _then(_value.copyWith( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + user_id: null == user_id + ? _value.user_id + : user_id // ignore: cast_nullable_to_non_nullable + as String, + from_latitude: null == from_latitude + ? _value.from_latitude + : from_latitude // ignore: cast_nullable_to_non_nullable + as Blob, + from_longitude: null == from_longitude + ? _value.from_longitude + : from_longitude // ignore: cast_nullable_to_non_nullable + as Blob, + to_latitude: freezed == to_latitude + ? _value.to_latitude + : to_latitude // ignore: cast_nullable_to_non_nullable + as Blob?, + to_longitude: freezed == to_longitude + ? _value.to_longitude + : to_longitude // ignore: cast_nullable_to_non_nullable + as Blob?, + routes: null == routes + ? _value.routes + : routes // ignore: cast_nullable_to_non_nullable + as List, + route_distance: freezed == route_distance + ? _value.route_distance + : route_distance // ignore: cast_nullable_to_non_nullable + as double?, + route_duration: freezed == route_duration + ? _value.route_duration + : route_duration // ignore: cast_nullable_to_non_nullable + as int?, + created_at: null == created_at + ? _value.created_at + : created_at // ignore: cast_nullable_to_non_nullable + as int, + updated_at: null == updated_at + ? _value.updated_at + : updated_at // ignore: cast_nullable_to_non_nullable + as int, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$EncryptedLocationJourneyImplCopyWith<$Res> + implements $EncryptedLocationJourneyCopyWith<$Res> { + factory _$$EncryptedLocationJourneyImplCopyWith( + _$EncryptedLocationJourneyImpl value, + $Res Function(_$EncryptedLocationJourneyImpl) then) = + __$$EncryptedLocationJourneyImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String? id, + String user_id, + @BlobConverter() Blob from_latitude, + @BlobConverter() Blob from_longitude, + @BlobConverter() Blob? to_latitude, + @BlobConverter() Blob? to_longitude, + List routes, + double? route_distance, + int? route_duration, + int created_at, + int updated_at, + String type}); +} + +/// @nodoc +class __$$EncryptedLocationJourneyImplCopyWithImpl<$Res> + extends _$EncryptedLocationJourneyCopyWithImpl<$Res, + _$EncryptedLocationJourneyImpl> + implements _$$EncryptedLocationJourneyImplCopyWith<$Res> { + __$$EncryptedLocationJourneyImplCopyWithImpl( + _$EncryptedLocationJourneyImpl _value, + $Res Function(_$EncryptedLocationJourneyImpl) _then) + : super(_value, _then); + + /// Create a copy of EncryptedLocationJourney + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = freezed, + Object? user_id = null, + Object? from_latitude = null, + Object? from_longitude = null, + Object? to_latitude = freezed, + Object? to_longitude = freezed, + Object? routes = null, + Object? route_distance = freezed, + Object? route_duration = freezed, + Object? created_at = null, + Object? updated_at = null, + Object? type = null, + }) { + return _then(_$EncryptedLocationJourneyImpl( + id: freezed == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String?, + user_id: null == user_id + ? _value.user_id + : user_id // ignore: cast_nullable_to_non_nullable + as String, + from_latitude: null == from_latitude + ? _value.from_latitude + : from_latitude // ignore: cast_nullable_to_non_nullable + as Blob, + from_longitude: null == from_longitude + ? _value.from_longitude + : from_longitude // ignore: cast_nullable_to_non_nullable + as Blob, + to_latitude: freezed == to_latitude + ? _value.to_latitude + : to_latitude // ignore: cast_nullable_to_non_nullable + as Blob?, + to_longitude: freezed == to_longitude + ? _value.to_longitude + : to_longitude // ignore: cast_nullable_to_non_nullable + as Blob?, + routes: null == routes + ? _value._routes + : routes // ignore: cast_nullable_to_non_nullable + as List, + route_distance: freezed == route_distance + ? _value.route_distance + : route_distance // ignore: cast_nullable_to_non_nullable + as double?, + route_duration: freezed == route_duration + ? _value.route_duration + : route_duration // ignore: cast_nullable_to_non_nullable + as int?, + created_at: null == created_at + ? _value.created_at + : created_at // ignore: cast_nullable_to_non_nullable + as int, + updated_at: null == updated_at + ? _value.updated_at + : updated_at // ignore: cast_nullable_to_non_nullable + as int, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$EncryptedLocationJourneyImpl extends _EncryptedLocationJourney { + const _$EncryptedLocationJourneyImpl( + {this.id, + required this.user_id, + @BlobConverter() required this.from_latitude, + @BlobConverter() required this.from_longitude, + @BlobConverter() this.to_latitude, + @BlobConverter() this.to_longitude, + final List routes = const [], + this.route_distance, + this.route_duration, + required this.created_at, + required this.updated_at, + required this.type}) + : _routes = routes, + super._(); + + factory _$EncryptedLocationJourneyImpl.fromJson(Map json) => + _$$EncryptedLocationJourneyImplFromJson(json); + + @override + final String? id; + @override + final String user_id; + @override + @BlobConverter() + final Blob from_latitude; + @override + @BlobConverter() + final Blob from_longitude; + @override + @BlobConverter() + final Blob? to_latitude; + @override + @BlobConverter() + final Blob? to_longitude; + final List _routes; + @override + @JsonKey() + List get routes { + if (_routes is EqualUnmodifiableListView) return _routes; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_routes); + } + + @override + final double? route_distance; + @override + final int? route_duration; + @override + final int created_at; + @override + final int updated_at; + @override + final String type; + + @override + String toString() { + return 'EncryptedLocationJourney(id: $id, user_id: $user_id, from_latitude: $from_latitude, from_longitude: $from_longitude, to_latitude: $to_latitude, to_longitude: $to_longitude, routes: $routes, route_distance: $route_distance, route_duration: $route_duration, created_at: $created_at, updated_at: $updated_at, type: $type)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$EncryptedLocationJourneyImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.user_id, user_id) || other.user_id == user_id) && + (identical(other.from_latitude, from_latitude) || + other.from_latitude == from_latitude) && + (identical(other.from_longitude, from_longitude) || + other.from_longitude == from_longitude) && + (identical(other.to_latitude, to_latitude) || + other.to_latitude == to_latitude) && + (identical(other.to_longitude, to_longitude) || + other.to_longitude == to_longitude) && + const DeepCollectionEquality().equals(other._routes, _routes) && + (identical(other.route_distance, route_distance) || + other.route_distance == route_distance) && + (identical(other.route_duration, route_duration) || + other.route_duration == route_duration) && + (identical(other.created_at, created_at) || + other.created_at == created_at) && + (identical(other.updated_at, updated_at) || + other.updated_at == updated_at) && + (identical(other.type, type) || other.type == type)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + id, + user_id, + from_latitude, + from_longitude, + to_latitude, + to_longitude, + const DeepCollectionEquality().hash(_routes), + route_distance, + route_duration, + created_at, + updated_at, + type); + + /// Create a copy of EncryptedLocationJourney + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$EncryptedLocationJourneyImplCopyWith<_$EncryptedLocationJourneyImpl> + get copyWith => __$$EncryptedLocationJourneyImplCopyWithImpl< + _$EncryptedLocationJourneyImpl>(this, _$identity); + + @override + Map toJson() { + return _$$EncryptedLocationJourneyImplToJson( + this, + ); + } +} + +abstract class _EncryptedLocationJourney extends EncryptedLocationJourney { + const factory _EncryptedLocationJourney( + {final String? id, + required final String user_id, + @BlobConverter() required final Blob from_latitude, + @BlobConverter() required final Blob from_longitude, + @BlobConverter() final Blob? to_latitude, + @BlobConverter() final Blob? to_longitude, + final List routes, + final double? route_distance, + final int? route_duration, + required final int created_at, + required final int updated_at, + required final String type}) = _$EncryptedLocationJourneyImpl; + const _EncryptedLocationJourney._() : super._(); + + factory _EncryptedLocationJourney.fromJson(Map json) = + _$EncryptedLocationJourneyImpl.fromJson; + + @override + String? get id; + @override + String get user_id; + @override + @BlobConverter() + Blob get from_latitude; + @override + @BlobConverter() + Blob get from_longitude; + @override + @BlobConverter() + Blob? get to_latitude; + @override + @BlobConverter() + Blob? get to_longitude; + @override + List get routes; + @override + double? get route_distance; + @override + int? get route_duration; + @override + int get created_at; + @override + int get updated_at; + @override + String get type; + + /// Create a copy of EncryptedLocationJourney + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$EncryptedLocationJourneyImplCopyWith<_$EncryptedLocationJourneyImpl> + get copyWith => throw _privateConstructorUsedError; +} + +EncryptedJourneyRoute _$EncryptedJourneyRouteFromJson( + Map json) { + return _EncryptedJourneyRoute.fromJson(json); +} + +/// @nodoc +mixin _$EncryptedJourneyRoute { + @BlobConverter() + Blob get latitude => throw _privateConstructorUsedError; + @BlobConverter() + Blob get longitude => throw _privateConstructorUsedError; + + /// Serializes this EncryptedJourneyRoute to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of EncryptedJourneyRoute + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $EncryptedJourneyRouteCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $EncryptedJourneyRouteCopyWith<$Res> { + factory $EncryptedJourneyRouteCopyWith(EncryptedJourneyRoute value, + $Res Function(EncryptedJourneyRoute) then) = + _$EncryptedJourneyRouteCopyWithImpl<$Res, EncryptedJourneyRoute>; + @useResult + $Res call({@BlobConverter() Blob latitude, @BlobConverter() Blob longitude}); +} + +/// @nodoc +class _$EncryptedJourneyRouteCopyWithImpl<$Res, + $Val extends EncryptedJourneyRoute> + implements $EncryptedJourneyRouteCopyWith<$Res> { + _$EncryptedJourneyRouteCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of EncryptedJourneyRoute + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? latitude = null, + Object? longitude = null, + }) { + return _then(_value.copyWith( + latitude: null == latitude + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as Blob, + longitude: null == longitude + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as Blob, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$EncryptedJourneyRouteImplCopyWith<$Res> + implements $EncryptedJourneyRouteCopyWith<$Res> { + factory _$$EncryptedJourneyRouteImplCopyWith( + _$EncryptedJourneyRouteImpl value, + $Res Function(_$EncryptedJourneyRouteImpl) then) = + __$$EncryptedJourneyRouteImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({@BlobConverter() Blob latitude, @BlobConverter() Blob longitude}); +} + +/// @nodoc +class __$$EncryptedJourneyRouteImplCopyWithImpl<$Res> + extends _$EncryptedJourneyRouteCopyWithImpl<$Res, + _$EncryptedJourneyRouteImpl> + implements _$$EncryptedJourneyRouteImplCopyWith<$Res> { + __$$EncryptedJourneyRouteImplCopyWithImpl(_$EncryptedJourneyRouteImpl _value, + $Res Function(_$EncryptedJourneyRouteImpl) _then) + : super(_value, _then); + + /// Create a copy of EncryptedJourneyRoute + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? latitude = null, + Object? longitude = null, + }) { + return _then(_$EncryptedJourneyRouteImpl( + latitude: null == latitude + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as Blob, + longitude: null == longitude + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as Blob, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$EncryptedJourneyRouteImpl implements _EncryptedJourneyRoute { + const _$EncryptedJourneyRouteImpl( + {@BlobConverter() required this.latitude, + @BlobConverter() required this.longitude}); + + factory _$EncryptedJourneyRouteImpl.fromJson(Map json) => + _$$EncryptedJourneyRouteImplFromJson(json); + + @override + @BlobConverter() + final Blob latitude; + @override + @BlobConverter() + final Blob longitude; + + @override + String toString() { + return 'EncryptedJourneyRoute(latitude: $latitude, longitude: $longitude)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$EncryptedJourneyRouteImpl && + (identical(other.latitude, latitude) || + other.latitude == latitude) && + (identical(other.longitude, longitude) || + other.longitude == longitude)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, latitude, longitude); + + /// Create a copy of EncryptedJourneyRoute + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$EncryptedJourneyRouteImplCopyWith<_$EncryptedJourneyRouteImpl> + get copyWith => __$$EncryptedJourneyRouteImplCopyWithImpl< + _$EncryptedJourneyRouteImpl>(this, _$identity); + + @override + Map toJson() { + return _$$EncryptedJourneyRouteImplToJson( + this, + ); + } +} + +abstract class _EncryptedJourneyRoute implements EncryptedJourneyRoute { + const factory _EncryptedJourneyRoute( + {@BlobConverter() required final Blob latitude, + @BlobConverter() required final Blob longitude}) = + _$EncryptedJourneyRouteImpl; + + factory _EncryptedJourneyRoute.fromJson(Map json) = + _$EncryptedJourneyRouteImpl.fromJson; + + @override + @BlobConverter() + Blob get latitude; + @override + @BlobConverter() + Blob get longitude; + + /// Create a copy of EncryptedJourneyRoute + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$EncryptedJourneyRouteImplCopyWith<_$EncryptedJourneyRouteImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/data/lib/api/location/journey/journey.g.dart b/data/lib/api/location/journey/journey.g.dart index 7efeefe8..5f82195f 100644 --- a/data/lib/api/location/journey/journey.g.dart +++ b/data/lib/api/location/journey/journey.g.dart @@ -21,9 +21,9 @@ _$LocationJourneyImpl _$$LocationJourneyImplFromJson( const [], route_distance: (json['route_distance'] as num?)?.toDouble(), route_duration: (json['route_duration'] as num?)?.toInt(), - created_at: (json['created_at'] as num?)?.toInt(), - update_at: (json['update_at'] as num?)?.toInt(), - type: json['type'] as String?, + created_at: (json['created_at'] as num).toInt(), + updated_at: (json['updated_at'] as num).toInt(), + type: json['type'] as String, ); Map _$$LocationJourneyImplToJson( @@ -39,7 +39,7 @@ Map _$$LocationJourneyImplToJson( 'route_distance': instance.route_distance, 'route_duration': instance.route_duration, 'created_at': instance.created_at, - 'update_at': instance.update_at, + 'updated_at': instance.updated_at, 'type': instance.type, }; @@ -54,3 +54,63 @@ Map _$$JourneyRouteImplToJson(_$JourneyRouteImpl instance) => 'latitude': instance.latitude, 'longitude': instance.longitude, }; + +_$EncryptedLocationJourneyImpl _$$EncryptedLocationJourneyImplFromJson( + Map json) => + _$EncryptedLocationJourneyImpl( + id: json['id'] as String?, + user_id: json['user_id'] as String, + from_latitude: const BlobConverter().fromJson(json['from_latitude']), + from_longitude: const BlobConverter().fromJson(json['from_longitude']), + to_latitude: const BlobConverter().fromJson(json['to_latitude']), + to_longitude: const BlobConverter().fromJson(json['to_longitude']), + routes: (json['routes'] as List?) + ?.map((e) => + EncryptedJourneyRoute.fromJson(e as Map)) + .toList() ?? + const [], + route_distance: (json['route_distance'] as num?)?.toDouble(), + route_duration: (json['route_duration'] as num?)?.toInt(), + created_at: (json['created_at'] as num).toInt(), + updated_at: (json['updated_at'] as num).toInt(), + type: json['type'] as String, + ); + +Map _$$EncryptedLocationJourneyImplToJson( + _$EncryptedLocationJourneyImpl instance) => + { + 'id': instance.id, + 'user_id': instance.user_id, + 'from_latitude': const BlobConverter().toJson(instance.from_latitude), + 'from_longitude': const BlobConverter().toJson(instance.from_longitude), + 'to_latitude': _$JsonConverterToJson( + instance.to_latitude, const BlobConverter().toJson), + 'to_longitude': _$JsonConverterToJson( + instance.to_longitude, const BlobConverter().toJson), + 'routes': instance.routes.map((e) => e.toJson()).toList(), + 'route_distance': instance.route_distance, + 'route_duration': instance.route_duration, + 'created_at': instance.created_at, + 'updated_at': instance.updated_at, + 'type': instance.type, + }; + +Json? _$JsonConverterToJson( + Value? value, + Json? Function(Value value) toJson, +) => + value == null ? null : toJson(value); + +_$EncryptedJourneyRouteImpl _$$EncryptedJourneyRouteImplFromJson( + Map json) => + _$EncryptedJourneyRouteImpl( + latitude: const BlobConverter().fromJson(json['latitude']), + longitude: const BlobConverter().fromJson(json['longitude']), + ); + +Map _$$EncryptedJourneyRouteImplToJson( + _$EncryptedJourneyRouteImpl instance) => + { + 'latitude': const BlobConverter().toJson(instance.latitude), + 'longitude': const BlobConverter().toJson(instance.longitude), + }; diff --git a/data/lib/api/location/location.dart b/data/lib/api/location/location.dart index 28d8564e..a009c502 100644 --- a/data/lib/api/location/location.dart +++ b/data/lib/api/location/location.dart @@ -1,15 +1,14 @@ //ignore_for_file: constant_identifier_names import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:data/converter/blob_converter.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; part 'location.freezed.dart'; -part 'location.g.dart'; -const USER_STATE_STEADY = 0; -const USER_STATE_MOVING = 1; +part 'location.g.dart'; @freezed class ApiLocation with _$ApiLocation { @@ -20,8 +19,7 @@ class ApiLocation with _$ApiLocation { required String user_id, required double latitude, required double longitude, - int? user_state, - int? created_at, + required int created_at, }) = _ApiLocation; factory ApiLocation.fromJson(Map data) => @@ -37,6 +35,31 @@ class ApiLocation with _$ApiLocation { Map toFireStore(ApiLocation space) => space.toJson(); } +@freezed +class EncryptedApiLocation with _$EncryptedApiLocation { + const EncryptedApiLocation._(); + + const factory EncryptedApiLocation({ + required String id, + required String user_id, + @BlobConverter() required Blob latitude, + @BlobConverter() required Blob longitude, + required int created_at, + }) = _EncryptedApiLocation; + + factory EncryptedApiLocation.fromJson(Map data) => + _$EncryptedApiLocationFromJson(data); + + factory EncryptedApiLocation.fromFireStore( + DocumentSnapshot> snapshot, + SnapshotOptions? options) { + Map? data = snapshot.data(); + return EncryptedApiLocation.fromJson(data!); + } + + Map toFireStore(ApiLocation space) => space.toJson(); +} + class LocationData { final double latitude; final double longitude; @@ -49,7 +72,8 @@ class LocationData { }); double distanceTo(LocationData other) { - return Geolocator.distanceBetween(latitude, longitude, other.latitude, other.longitude); + return Geolocator.distanceBetween( + latitude, longitude, other.latitude, other.longitude); } } @@ -58,4 +82,4 @@ class MapTypeInfo { final int index; MapTypeInfo(this.mapType, this.index); -} \ No newline at end of file +} diff --git a/data/lib/api/location/location.freezed.dart b/data/lib/api/location/location.freezed.dart index e7093584..4841fcd7 100644 --- a/data/lib/api/location/location.freezed.dart +++ b/data/lib/api/location/location.freezed.dart @@ -24,11 +24,14 @@ mixin _$ApiLocation { String get user_id => throw _privateConstructorUsedError; double get latitude => throw _privateConstructorUsedError; double get longitude => throw _privateConstructorUsedError; - int? get user_state => throw _privateConstructorUsedError; - int? get created_at => throw _privateConstructorUsedError; + int get created_at => throw _privateConstructorUsedError; + /// Serializes this ApiLocation to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiLocation + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiLocationCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -44,8 +47,7 @@ abstract class $ApiLocationCopyWith<$Res> { String user_id, double latitude, double longitude, - int? user_state, - int? created_at}); + int created_at}); } /// @nodoc @@ -58,6 +60,8 @@ class _$ApiLocationCopyWithImpl<$Res, $Val extends ApiLocation> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiLocation + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -65,8 +69,7 @@ class _$ApiLocationCopyWithImpl<$Res, $Val extends ApiLocation> Object? user_id = null, Object? latitude = null, Object? longitude = null, - Object? user_state = freezed, - Object? created_at = freezed, + Object? created_at = null, }) { return _then(_value.copyWith( id: null == id @@ -85,14 +88,10 @@ class _$ApiLocationCopyWithImpl<$Res, $Val extends ApiLocation> ? _value.longitude : longitude // ignore: cast_nullable_to_non_nullable as double, - user_state: freezed == user_state - ? _value.user_state - : user_state // ignore: cast_nullable_to_non_nullable - as int?, - created_at: freezed == created_at + created_at: null == created_at ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable - as int?, + as int, ) as $Val); } } @@ -110,8 +109,7 @@ abstract class _$$ApiLocationImplCopyWith<$Res> String user_id, double latitude, double longitude, - int? user_state, - int? created_at}); + int created_at}); } /// @nodoc @@ -122,6 +120,8 @@ class __$$ApiLocationImplCopyWithImpl<$Res> _$ApiLocationImpl _value, $Res Function(_$ApiLocationImpl) _then) : super(_value, _then); + /// Create a copy of ApiLocation + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -129,8 +129,7 @@ class __$$ApiLocationImplCopyWithImpl<$Res> Object? user_id = null, Object? latitude = null, Object? longitude = null, - Object? user_state = freezed, - Object? created_at = freezed, + Object? created_at = null, }) { return _then(_$ApiLocationImpl( id: null == id @@ -149,14 +148,10 @@ class __$$ApiLocationImplCopyWithImpl<$Res> ? _value.longitude : longitude // ignore: cast_nullable_to_non_nullable as double, - user_state: freezed == user_state - ? _value.user_state - : user_state // ignore: cast_nullable_to_non_nullable - as int?, - created_at: freezed == created_at + created_at: null == created_at ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable - as int?, + as int, )); } } @@ -169,8 +164,7 @@ class _$ApiLocationImpl extends _ApiLocation { required this.user_id, required this.latitude, required this.longitude, - this.user_state, - this.created_at}) + required this.created_at}) : super._(); factory _$ApiLocationImpl.fromJson(Map json) => @@ -185,13 +179,11 @@ class _$ApiLocationImpl extends _ApiLocation { @override final double longitude; @override - final int? user_state; - @override - final int? created_at; + final int created_at; @override String toString() { - return 'ApiLocation(id: $id, user_id: $user_id, latitude: $latitude, longitude: $longitude, user_state: $user_state, created_at: $created_at)'; + return 'ApiLocation(id: $id, user_id: $user_id, latitude: $latitude, longitude: $longitude, created_at: $created_at)'; } @override @@ -205,18 +197,18 @@ class _$ApiLocationImpl extends _ApiLocation { other.latitude == latitude) && (identical(other.longitude, longitude) || other.longitude == longitude) && - (identical(other.user_state, user_state) || - other.user_state == user_state) && (identical(other.created_at, created_at) || other.created_at == created_at)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash( - runtimeType, id, user_id, latitude, longitude, user_state, created_at); + int get hashCode => + Object.hash(runtimeType, id, user_id, latitude, longitude, created_at); - @JsonKey(ignore: true) + /// Create a copy of ApiLocation + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiLocationImplCopyWith<_$ApiLocationImpl> get copyWith => @@ -236,8 +228,7 @@ abstract class _ApiLocation extends ApiLocation { required final String user_id, required final double latitude, required final double longitude, - final int? user_state, - final int? created_at}) = _$ApiLocationImpl; + required final int created_at}) = _$ApiLocationImpl; const _ApiLocation._() : super._(); factory _ApiLocation.fromJson(Map json) = @@ -252,11 +243,260 @@ abstract class _ApiLocation extends ApiLocation { @override double get longitude; @override - int? get user_state; - @override - int? get created_at; + int get created_at; + + /// Create a copy of ApiLocation + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiLocationImplCopyWith<_$ApiLocationImpl> get copyWith => throw _privateConstructorUsedError; } + +EncryptedApiLocation _$EncryptedApiLocationFromJson(Map json) { + return _EncryptedApiLocation.fromJson(json); +} + +/// @nodoc +mixin _$EncryptedApiLocation { + String get id => throw _privateConstructorUsedError; + String get user_id => throw _privateConstructorUsedError; + @BlobConverter() + Blob get latitude => throw _privateConstructorUsedError; + @BlobConverter() + Blob get longitude => throw _privateConstructorUsedError; + int get created_at => throw _privateConstructorUsedError; + + /// Serializes this EncryptedApiLocation to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of EncryptedApiLocation + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $EncryptedApiLocationCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $EncryptedApiLocationCopyWith<$Res> { + factory $EncryptedApiLocationCopyWith(EncryptedApiLocation value, + $Res Function(EncryptedApiLocation) then) = + _$EncryptedApiLocationCopyWithImpl<$Res, EncryptedApiLocation>; + @useResult + $Res call( + {String id, + String user_id, + @BlobConverter() Blob latitude, + @BlobConverter() Blob longitude, + int created_at}); +} + +/// @nodoc +class _$EncryptedApiLocationCopyWithImpl<$Res, + $Val extends EncryptedApiLocation> + implements $EncryptedApiLocationCopyWith<$Res> { + _$EncryptedApiLocationCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of EncryptedApiLocation + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? user_id = null, + Object? latitude = null, + Object? longitude = null, + Object? created_at = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + user_id: null == user_id + ? _value.user_id + : user_id // ignore: cast_nullable_to_non_nullable + as String, + latitude: null == latitude + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as Blob, + longitude: null == longitude + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as Blob, + created_at: null == created_at + ? _value.created_at + : created_at // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$EncryptedApiLocationImplCopyWith<$Res> + implements $EncryptedApiLocationCopyWith<$Res> { + factory _$$EncryptedApiLocationImplCopyWith(_$EncryptedApiLocationImpl value, + $Res Function(_$EncryptedApiLocationImpl) then) = + __$$EncryptedApiLocationImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String id, + String user_id, + @BlobConverter() Blob latitude, + @BlobConverter() Blob longitude, + int created_at}); +} + +/// @nodoc +class __$$EncryptedApiLocationImplCopyWithImpl<$Res> + extends _$EncryptedApiLocationCopyWithImpl<$Res, _$EncryptedApiLocationImpl> + implements _$$EncryptedApiLocationImplCopyWith<$Res> { + __$$EncryptedApiLocationImplCopyWithImpl(_$EncryptedApiLocationImpl _value, + $Res Function(_$EncryptedApiLocationImpl) _then) + : super(_value, _then); + + /// Create a copy of EncryptedApiLocation + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? user_id = null, + Object? latitude = null, + Object? longitude = null, + Object? created_at = null, + }) { + return _then(_$EncryptedApiLocationImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + user_id: null == user_id + ? _value.user_id + : user_id // ignore: cast_nullable_to_non_nullable + as String, + latitude: null == latitude + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as Blob, + longitude: null == longitude + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as Blob, + created_at: null == created_at + ? _value.created_at + : created_at // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$EncryptedApiLocationImpl extends _EncryptedApiLocation { + const _$EncryptedApiLocationImpl( + {required this.id, + required this.user_id, + @BlobConverter() required this.latitude, + @BlobConverter() required this.longitude, + required this.created_at}) + : super._(); + + factory _$EncryptedApiLocationImpl.fromJson(Map json) => + _$$EncryptedApiLocationImplFromJson(json); + + @override + final String id; + @override + final String user_id; + @override + @BlobConverter() + final Blob latitude; + @override + @BlobConverter() + final Blob longitude; + @override + final int created_at; + + @override + String toString() { + return 'EncryptedApiLocation(id: $id, user_id: $user_id, latitude: $latitude, longitude: $longitude, created_at: $created_at)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$EncryptedApiLocationImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.user_id, user_id) || other.user_id == user_id) && + (identical(other.latitude, latitude) || + other.latitude == latitude) && + (identical(other.longitude, longitude) || + other.longitude == longitude) && + (identical(other.created_at, created_at) || + other.created_at == created_at)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => + Object.hash(runtimeType, id, user_id, latitude, longitude, created_at); + + /// Create a copy of EncryptedApiLocation + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$EncryptedApiLocationImplCopyWith<_$EncryptedApiLocationImpl> + get copyWith => + __$$EncryptedApiLocationImplCopyWithImpl<_$EncryptedApiLocationImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$EncryptedApiLocationImplToJson( + this, + ); + } +} + +abstract class _EncryptedApiLocation extends EncryptedApiLocation { + const factory _EncryptedApiLocation( + {required final String id, + required final String user_id, + @BlobConverter() required final Blob latitude, + @BlobConverter() required final Blob longitude, + required final int created_at}) = _$EncryptedApiLocationImpl; + const _EncryptedApiLocation._() : super._(); + + factory _EncryptedApiLocation.fromJson(Map json) = + _$EncryptedApiLocationImpl.fromJson; + + @override + String get id; + @override + String get user_id; + @override + @BlobConverter() + Blob get latitude; + @override + @BlobConverter() + Blob get longitude; + @override + int get created_at; + + /// Create a copy of EncryptedApiLocation + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$EncryptedApiLocationImplCopyWith<_$EncryptedApiLocationImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/data/lib/api/location/location.g.dart b/data/lib/api/location/location.g.dart index c0321b29..1a66d526 100644 --- a/data/lib/api/location/location.g.dart +++ b/data/lib/api/location/location.g.dart @@ -12,8 +12,7 @@ _$ApiLocationImpl _$$ApiLocationImplFromJson(Map json) => user_id: json['user_id'] as String, latitude: (json['latitude'] as num).toDouble(), longitude: (json['longitude'] as num).toDouble(), - user_state: (json['user_state'] as num?)?.toInt(), - created_at: (json['created_at'] as num?)?.toInt(), + created_at: (json['created_at'] as num).toInt(), ); Map _$$ApiLocationImplToJson(_$ApiLocationImpl instance) => @@ -22,6 +21,25 @@ Map _$$ApiLocationImplToJson(_$ApiLocationImpl instance) => 'user_id': instance.user_id, 'latitude': instance.latitude, 'longitude': instance.longitude, - 'user_state': instance.user_state, + 'created_at': instance.created_at, + }; + +_$EncryptedApiLocationImpl _$$EncryptedApiLocationImplFromJson( + Map json) => + _$EncryptedApiLocationImpl( + id: json['id'] as String, + user_id: json['user_id'] as String, + latitude: const BlobConverter().fromJson(json['latitude']), + longitude: const BlobConverter().fromJson(json['longitude']), + created_at: (json['created_at'] as num).toInt(), + ); + +Map _$$EncryptedApiLocationImplToJson( + _$EncryptedApiLocationImpl instance) => + { + 'id': instance.id, + 'user_id': instance.user_id, + 'latitude': const BlobConverter().toJson(instance.latitude), + 'longitude': const BlobConverter().toJson(instance.longitude), 'created_at': instance.created_at, }; diff --git a/data/lib/api/message/message_models.freezed.dart b/data/lib/api/message/message_models.freezed.dart index 700ab58d..9506f92f 100644 --- a/data/lib/api/message/message_models.freezed.dart +++ b/data/lib/api/message/message_models.freezed.dart @@ -31,8 +31,12 @@ mixin _$ApiThread { @ServerTimestampConverter() DateTime? get last_message_at => throw _privateConstructorUsedError; + /// Serializes this ApiThread to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiThread + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiThreadCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -64,6 +68,8 @@ class _$ApiThreadCopyWithImpl<$Res, $Val extends ApiThread> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiThread + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -146,6 +152,8 @@ class __$$ApiThreadImplCopyWithImpl<$Res> _$ApiThreadImpl _value, $Res Function(_$ApiThreadImpl) _then) : super(_value, _then); + /// Create a copy of ApiThread + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -291,7 +299,7 @@ class _$ApiThreadImpl extends _ApiThread { other.last_message_at == last_message_at)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -305,7 +313,9 @@ class _$ApiThreadImpl extends _ApiThread { last_message, last_message_at); - @JsonKey(ignore: true) + /// Create a copy of ApiThread + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiThreadImplCopyWith<_$ApiThreadImpl> get copyWith => @@ -355,8 +365,11 @@ abstract class _ApiThread extends ApiThread { @override @ServerTimestampConverter() DateTime? get last_message_at; + + /// Create a copy of ApiThread + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiThreadImplCopyWith<_$ApiThreadImpl> get copyWith => throw _privateConstructorUsedError; } @@ -376,8 +389,12 @@ mixin _$ApiThreadMessage { @ServerTimestampConverter() DateTime? get created_at => throw _privateConstructorUsedError; + /// Serializes this ApiThreadMessage to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiThreadMessage + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiThreadMessageCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -408,6 +425,8 @@ class _$ApiThreadMessageCopyWithImpl<$Res, $Val extends ApiThreadMessage> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiThreadMessage + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -478,6 +497,8 @@ class __$$ApiThreadMessageImplCopyWithImpl<$Res> $Res Function(_$ApiThreadMessageImpl) _then) : super(_value, _then); + /// Create a copy of ApiThreadMessage + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -593,7 +614,7 @@ class _$ApiThreadMessageImpl extends _ApiThreadMessage { other.created_at == created_at)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -605,7 +626,9 @@ class _$ApiThreadMessageImpl extends _ApiThreadMessage { const DeepCollectionEquality().hash(_archived_for), created_at); - @JsonKey(ignore: true) + /// Create a copy of ApiThreadMessage + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiThreadMessageImplCopyWith<_$ApiThreadMessageImpl> get copyWith => @@ -650,8 +673,11 @@ abstract class _ApiThreadMessage extends ApiThreadMessage { @override @ServerTimestampConverter() DateTime? get created_at; + + /// Create a copy of ApiThreadMessage + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiThreadMessageImplCopyWith<_$ApiThreadMessageImpl> get copyWith => throw _privateConstructorUsedError; } @@ -667,8 +693,12 @@ mixin _$ThreadInfo { throw _privateConstructorUsedError; List get members => throw _privateConstructorUsedError; + /// Serializes this ThreadInfo to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ThreadInfo + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ThreadInfoCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -697,6 +727,8 @@ class _$ThreadInfoCopyWithImpl<$Res, $Val extends ThreadInfo> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ThreadInfo + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -720,6 +752,8 @@ class _$ThreadInfoCopyWithImpl<$Res, $Val extends ThreadInfo> ) as $Val); } + /// Create a copy of ThreadInfo + /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') $ApiThreadCopyWith<$Res> get thread { @@ -754,6 +788,8 @@ class __$$ThreadInfoImplCopyWithImpl<$Res> _$ThreadInfoImpl _value, $Res Function(_$ThreadInfoImpl) _then) : super(_value, _then); + /// Create a copy of ThreadInfo + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -826,7 +862,7 @@ class _$ThreadInfoImpl extends _ThreadInfo { const DeepCollectionEquality().equals(other._members, _members)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -834,7 +870,9 @@ class _$ThreadInfoImpl extends _ThreadInfo { const DeepCollectionEquality().hash(_threadMessage), const DeepCollectionEquality().hash(_members)); - @JsonKey(ignore: true) + /// Create a copy of ThreadInfo + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ThreadInfoImplCopyWith<_$ThreadInfoImpl> get copyWith => @@ -864,8 +902,11 @@ abstract class _ThreadInfo extends ThreadInfo { List get threadMessage; @override List get members; + + /// Create a copy of ThreadInfo + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ThreadInfoImplCopyWith<_$ThreadInfoImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/data/lib/api/place/api_place.freezed.dart b/data/lib/api/place/api_place.freezed.dart index a492dca8..149e2b73 100644 --- a/data/lib/api/place/api_place.freezed.dart +++ b/data/lib/api/place/api_place.freezed.dart @@ -31,8 +31,12 @@ mixin _$ApiPlace { DateTime? get created_at => throw _privateConstructorUsedError; List get space_member_ids => throw _privateConstructorUsedError; + /// Serializes this ApiPlace to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiPlace + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiPlaceCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -64,6 +68,8 @@ class _$ApiPlaceCopyWithImpl<$Res, $Val extends ApiPlace> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiPlace + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -146,6 +152,8 @@ class __$$ApiPlaceImplCopyWithImpl<$Res> _$ApiPlaceImpl _value, $Res Function(_$ApiPlaceImpl) _then) : super(_value, _then); + /// Create a copy of ApiPlace + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -274,7 +282,7 @@ class _$ApiPlaceImpl extends _ApiPlace { .equals(other._space_member_ids, _space_member_ids)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -288,7 +296,9 @@ class _$ApiPlaceImpl extends _ApiPlace { created_at, const DeepCollectionEquality().hash(_space_member_ids)); - @JsonKey(ignore: true) + /// Create a copy of ApiPlace + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiPlaceImplCopyWith<_$ApiPlaceImpl> get copyWith => @@ -337,8 +347,11 @@ abstract class _ApiPlace extends ApiPlace { DateTime? get created_at; @override List get space_member_ids; + + /// Create a copy of ApiPlace + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiPlaceImplCopyWith<_$ApiPlaceImpl> get copyWith => throw _privateConstructorUsedError; } @@ -356,8 +369,12 @@ mixin _$ApiPlaceMemberSetting { List get arrival_alert_for => throw _privateConstructorUsedError; List get leave_alert_for => throw _privateConstructorUsedError; + /// Serializes this ApiPlaceMemberSetting to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiPlaceMemberSetting + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiPlaceMemberSettingCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -387,6 +404,8 @@ class _$ApiPlaceMemberSettingCopyWithImpl<$Res, // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiPlaceMemberSetting + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -447,6 +466,8 @@ class __$$ApiPlaceMemberSettingImplCopyWithImpl<$Res> $Res Function(_$ApiPlaceMemberSettingImpl) _then) : super(_value, _then); + /// Create a copy of ApiPlaceMemberSetting + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -544,7 +565,7 @@ class _$ApiPlaceMemberSettingImpl extends _ApiPlaceMemberSetting { .equals(other._leave_alert_for, _leave_alert_for)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -554,7 +575,9 @@ class _$ApiPlaceMemberSettingImpl extends _ApiPlaceMemberSetting { const DeepCollectionEquality().hash(_arrival_alert_for), const DeepCollectionEquality().hash(_leave_alert_for)); - @JsonKey(ignore: true) + /// Create a copy of ApiPlaceMemberSetting + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiPlaceMemberSettingImplCopyWith<_$ApiPlaceMemberSettingImpl> @@ -591,8 +614,11 @@ abstract class _ApiPlaceMemberSetting extends ApiPlaceMemberSetting { List get arrival_alert_for; @override List get leave_alert_for; + + /// Create a copy of ApiPlaceMemberSetting + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiPlaceMemberSettingImplCopyWith<_$ApiPlaceMemberSettingImpl> get copyWith => throw _privateConstructorUsedError; } @@ -609,8 +635,12 @@ mixin _$ApiNearbyPlace { double get lat => throw _privateConstructorUsedError; double get lng => throw _privateConstructorUsedError; + /// Serializes this ApiNearbyPlace to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiNearbyPlace + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiNearbyPlaceCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -639,6 +669,8 @@ class _$ApiNearbyPlaceCopyWithImpl<$Res, $Val extends ApiNearbyPlace> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiNearbyPlace + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -697,6 +729,8 @@ class __$$ApiNearbyPlaceImplCopyWithImpl<$Res> _$ApiNearbyPlaceImpl _value, $Res Function(_$ApiNearbyPlaceImpl) _then) : super(_value, _then); + /// Create a copy of ApiNearbyPlace + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -774,12 +808,14 @@ class _$ApiNearbyPlaceImpl extends _ApiNearbyPlace { (identical(other.lng, lng) || other.lng == lng)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash(runtimeType, id, name, formatted_address, lat, lng); - @JsonKey(ignore: true) + /// Create a copy of ApiNearbyPlace + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiNearbyPlaceImplCopyWith<_$ApiNearbyPlaceImpl> get copyWith => @@ -816,8 +852,11 @@ abstract class _ApiNearbyPlace extends ApiNearbyPlace { double get lat; @override double get lng; + + /// Create a copy of ApiNearbyPlace + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiNearbyPlaceImplCopyWith<_$ApiNearbyPlaceImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/data/lib/api/space/api_group_key_model.dart b/data/lib/api/space/api_group_key_model.dart new file mode 100644 index 00000000..972051e1 --- /dev/null +++ b/data/lib/api/space/api_group_key_model.dart @@ -0,0 +1,99 @@ + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:data/converter/blob_converter.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'api_group_key_model.freezed.dart'; +part 'api_group_key_model.g.dart'; + +@freezed +class ApiGroupKey with _$ApiGroupKey { + const ApiGroupKey._(); + + const factory ApiGroupKey({ + required int doc_updated_at, + @Default({}) Map member_keys, + }) = _ApiGroupKey; + + factory ApiGroupKey.fromJson(Map data) => + _$ApiGroupKeyFromJson(data); + + factory ApiGroupKey.fromFireStore( + DocumentSnapshot> snapshot, + SnapshotOptions? options) { + Map? data = snapshot.data(); + return ApiGroupKey.fromJson(data!); + } + + Map toFireStore(ApiGroupKey key) => key.toJson(); + +} + +@freezed +class ApiMemberKeyData with _$ApiMemberKeyData { + const factory ApiMemberKeyData({ + @Default(0)int member_device_id, + @Default(0) int data_updated_at, + @Default([]) List distributions, + }) = _ApiMemberKeyData; + + factory ApiMemberKeyData.fromJson(Map data) => + _$ApiMemberKeyDataFromJson(data); + +} + +@freezed +class EncryptedDistribution with _$EncryptedDistribution { + const EncryptedDistribution._(); + + const factory EncryptedDistribution({ + @Default("") String recipientId, + @BlobConverter() required Blob ephemeralPub, + @BlobConverter() required Blob iv, + @BlobConverter() required Blob ciphertext, + }) = _EncryptedDistribution; + + factory EncryptedDistribution.fromJson(Map data) => + _$EncryptedDistributionFromJson(data); + + void validateFieldSizes() { + if (ephemeralPub.bytes.length != 33 && ephemeralPub.bytes.isNotEmpty) { + throw ArgumentError( + "Invalid size for ephemeralPub: expected 33 bytes, got ${ephemeralPub.bytes.length} bytes."); + } + if (iv.bytes.length != 16 && iv.bytes.isNotEmpty) { + throw ArgumentError( + "Invalid size for iv: expected 16 bytes, got ${iv.bytes.length} bytes."); + } + if (ciphertext.bytes.length > 64 * 1024 && ciphertext.bytes.isNotEmpty) { + throw ArgumentError( + "Invalid size for ciphertext: maximum allowed size is 64 KB, got ${ciphertext.bytes.length} bytes."); + } + } +} + +@freezed +class ApiSenderKeyRecord with _$ApiSenderKeyRecord { + const ApiSenderKeyRecord._(); + + const factory ApiSenderKeyRecord({ + required String id, + required int device_id, + required String distribution_id, + @BlobConverter() required Blob record, + @Default('') String address, + required int created_at, + }) = _ApiSenderKeyRecord; + + factory ApiSenderKeyRecord.fromJson(Map json) => + _$ApiSenderKeyRecordFromJson(json); + + factory ApiSenderKeyRecord.fromFireStore( + DocumentSnapshot> snapshot, + SnapshotOptions? options) { + Map? data = snapshot.data(); + return ApiSenderKeyRecord.fromJson(data!); + } + + Map toFireStore(ApiSenderKeyRecord instance) => instance.toJson(); +} diff --git a/data/lib/api/space/api_group_key_model.freezed.dart b/data/lib/api/space/api_group_key_model.freezed.dart new file mode 100644 index 00000000..e00af8ba --- /dev/null +++ b/data/lib/api/space/api_group_key_model.freezed.dart @@ -0,0 +1,905 @@ +// 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 'api_group_key_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'); + +ApiGroupKey _$ApiGroupKeyFromJson(Map json) { + return _ApiGroupKey.fromJson(json); +} + +/// @nodoc +mixin _$ApiGroupKey { + int get doc_updated_at => throw _privateConstructorUsedError; + Map get member_keys => + throw _privateConstructorUsedError; + + /// Serializes this ApiGroupKey to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ApiGroupKey + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ApiGroupKeyCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ApiGroupKeyCopyWith<$Res> { + factory $ApiGroupKeyCopyWith( + ApiGroupKey value, $Res Function(ApiGroupKey) then) = + _$ApiGroupKeyCopyWithImpl<$Res, ApiGroupKey>; + @useResult + $Res call({int doc_updated_at, Map member_keys}); +} + +/// @nodoc +class _$ApiGroupKeyCopyWithImpl<$Res, $Val extends ApiGroupKey> + implements $ApiGroupKeyCopyWith<$Res> { + _$ApiGroupKeyCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ApiGroupKey + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? doc_updated_at = null, + Object? member_keys = null, + }) { + return _then(_value.copyWith( + doc_updated_at: null == doc_updated_at + ? _value.doc_updated_at + : doc_updated_at // ignore: cast_nullable_to_non_nullable + as int, + member_keys: null == member_keys + ? _value.member_keys + : member_keys // ignore: cast_nullable_to_non_nullable + as Map, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ApiGroupKeyImplCopyWith<$Res> + implements $ApiGroupKeyCopyWith<$Res> { + factory _$$ApiGroupKeyImplCopyWith( + _$ApiGroupKeyImpl value, $Res Function(_$ApiGroupKeyImpl) then) = + __$$ApiGroupKeyImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({int doc_updated_at, Map member_keys}); +} + +/// @nodoc +class __$$ApiGroupKeyImplCopyWithImpl<$Res> + extends _$ApiGroupKeyCopyWithImpl<$Res, _$ApiGroupKeyImpl> + implements _$$ApiGroupKeyImplCopyWith<$Res> { + __$$ApiGroupKeyImplCopyWithImpl( + _$ApiGroupKeyImpl _value, $Res Function(_$ApiGroupKeyImpl) _then) + : super(_value, _then); + + /// Create a copy of ApiGroupKey + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? doc_updated_at = null, + Object? member_keys = null, + }) { + return _then(_$ApiGroupKeyImpl( + doc_updated_at: null == doc_updated_at + ? _value.doc_updated_at + : doc_updated_at // ignore: cast_nullable_to_non_nullable + as int, + member_keys: null == member_keys + ? _value._member_keys + : member_keys // ignore: cast_nullable_to_non_nullable + as Map, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ApiGroupKeyImpl extends _ApiGroupKey { + const _$ApiGroupKeyImpl( + {required this.doc_updated_at, + final Map member_keys = const {}}) + : _member_keys = member_keys, + super._(); + + factory _$ApiGroupKeyImpl.fromJson(Map json) => + _$$ApiGroupKeyImplFromJson(json); + + @override + final int doc_updated_at; + final Map _member_keys; + @override + @JsonKey() + Map get member_keys { + if (_member_keys is EqualUnmodifiableMapView) return _member_keys; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_member_keys); + } + + @override + String toString() { + return 'ApiGroupKey(doc_updated_at: $doc_updated_at, member_keys: $member_keys)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ApiGroupKeyImpl && + (identical(other.doc_updated_at, doc_updated_at) || + other.doc_updated_at == doc_updated_at) && + const DeepCollectionEquality() + .equals(other._member_keys, _member_keys)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, doc_updated_at, + const DeepCollectionEquality().hash(_member_keys)); + + /// Create a copy of ApiGroupKey + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ApiGroupKeyImplCopyWith<_$ApiGroupKeyImpl> get copyWith => + __$$ApiGroupKeyImplCopyWithImpl<_$ApiGroupKeyImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ApiGroupKeyImplToJson( + this, + ); + } +} + +abstract class _ApiGroupKey extends ApiGroupKey { + const factory _ApiGroupKey( + {required final int doc_updated_at, + final Map member_keys}) = _$ApiGroupKeyImpl; + const _ApiGroupKey._() : super._(); + + factory _ApiGroupKey.fromJson(Map json) = + _$ApiGroupKeyImpl.fromJson; + + @override + int get doc_updated_at; + @override + Map get member_keys; + + /// Create a copy of ApiGroupKey + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ApiGroupKeyImplCopyWith<_$ApiGroupKeyImpl> get copyWith => + throw _privateConstructorUsedError; +} + +ApiMemberKeyData _$ApiMemberKeyDataFromJson(Map json) { + return _ApiMemberKeyData.fromJson(json); +} + +/// @nodoc +mixin _$ApiMemberKeyData { + int get member_device_id => throw _privateConstructorUsedError; + int get data_updated_at => throw _privateConstructorUsedError; + List get distributions => + throw _privateConstructorUsedError; + + /// Serializes this ApiMemberKeyData to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ApiMemberKeyData + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ApiMemberKeyDataCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ApiMemberKeyDataCopyWith<$Res> { + factory $ApiMemberKeyDataCopyWith( + ApiMemberKeyData value, $Res Function(ApiMemberKeyData) then) = + _$ApiMemberKeyDataCopyWithImpl<$Res, ApiMemberKeyData>; + @useResult + $Res call( + {int member_device_id, + int data_updated_at, + List distributions}); +} + +/// @nodoc +class _$ApiMemberKeyDataCopyWithImpl<$Res, $Val extends ApiMemberKeyData> + implements $ApiMemberKeyDataCopyWith<$Res> { + _$ApiMemberKeyDataCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ApiMemberKeyData + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? member_device_id = null, + Object? data_updated_at = null, + Object? distributions = null, + }) { + return _then(_value.copyWith( + member_device_id: null == member_device_id + ? _value.member_device_id + : member_device_id // ignore: cast_nullable_to_non_nullable + as int, + data_updated_at: null == data_updated_at + ? _value.data_updated_at + : data_updated_at // ignore: cast_nullable_to_non_nullable + as int, + distributions: null == distributions + ? _value.distributions + : distributions // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ApiMemberKeyDataImplCopyWith<$Res> + implements $ApiMemberKeyDataCopyWith<$Res> { + factory _$$ApiMemberKeyDataImplCopyWith(_$ApiMemberKeyDataImpl value, + $Res Function(_$ApiMemberKeyDataImpl) then) = + __$$ApiMemberKeyDataImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int member_device_id, + int data_updated_at, + List distributions}); +} + +/// @nodoc +class __$$ApiMemberKeyDataImplCopyWithImpl<$Res> + extends _$ApiMemberKeyDataCopyWithImpl<$Res, _$ApiMemberKeyDataImpl> + implements _$$ApiMemberKeyDataImplCopyWith<$Res> { + __$$ApiMemberKeyDataImplCopyWithImpl(_$ApiMemberKeyDataImpl _value, + $Res Function(_$ApiMemberKeyDataImpl) _then) + : super(_value, _then); + + /// Create a copy of ApiMemberKeyData + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? member_device_id = null, + Object? data_updated_at = null, + Object? distributions = null, + }) { + return _then(_$ApiMemberKeyDataImpl( + member_device_id: null == member_device_id + ? _value.member_device_id + : member_device_id // ignore: cast_nullable_to_non_nullable + as int, + data_updated_at: null == data_updated_at + ? _value.data_updated_at + : data_updated_at // ignore: cast_nullable_to_non_nullable + as int, + distributions: null == distributions + ? _value._distributions + : distributions // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ApiMemberKeyDataImpl implements _ApiMemberKeyData { + const _$ApiMemberKeyDataImpl( + {this.member_device_id = 0, + this.data_updated_at = 0, + final List distributions = const []}) + : _distributions = distributions; + + factory _$ApiMemberKeyDataImpl.fromJson(Map json) => + _$$ApiMemberKeyDataImplFromJson(json); + + @override + @JsonKey() + final int member_device_id; + @override + @JsonKey() + final int data_updated_at; + final List _distributions; + @override + @JsonKey() + List get distributions { + if (_distributions is EqualUnmodifiableListView) return _distributions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_distributions); + } + + @override + String toString() { + return 'ApiMemberKeyData(member_device_id: $member_device_id, data_updated_at: $data_updated_at, distributions: $distributions)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ApiMemberKeyDataImpl && + (identical(other.member_device_id, member_device_id) || + other.member_device_id == member_device_id) && + (identical(other.data_updated_at, data_updated_at) || + other.data_updated_at == data_updated_at) && + const DeepCollectionEquality() + .equals(other._distributions, _distributions)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, member_device_id, + data_updated_at, const DeepCollectionEquality().hash(_distributions)); + + /// Create a copy of ApiMemberKeyData + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ApiMemberKeyDataImplCopyWith<_$ApiMemberKeyDataImpl> get copyWith => + __$$ApiMemberKeyDataImplCopyWithImpl<_$ApiMemberKeyDataImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ApiMemberKeyDataImplToJson( + this, + ); + } +} + +abstract class _ApiMemberKeyData implements ApiMemberKeyData { + const factory _ApiMemberKeyData( + {final int member_device_id, + final int data_updated_at, + final List distributions}) = + _$ApiMemberKeyDataImpl; + + factory _ApiMemberKeyData.fromJson(Map json) = + _$ApiMemberKeyDataImpl.fromJson; + + @override + int get member_device_id; + @override + int get data_updated_at; + @override + List get distributions; + + /// Create a copy of ApiMemberKeyData + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ApiMemberKeyDataImplCopyWith<_$ApiMemberKeyDataImpl> get copyWith => + throw _privateConstructorUsedError; +} + +EncryptedDistribution _$EncryptedDistributionFromJson( + Map json) { + return _EncryptedDistribution.fromJson(json); +} + +/// @nodoc +mixin _$EncryptedDistribution { + String get recipientId => throw _privateConstructorUsedError; + @BlobConverter() + Blob get ephemeralPub => throw _privateConstructorUsedError; + @BlobConverter() + Blob get iv => throw _privateConstructorUsedError; + @BlobConverter() + Blob get ciphertext => throw _privateConstructorUsedError; + + /// Serializes this EncryptedDistribution to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of EncryptedDistribution + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $EncryptedDistributionCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $EncryptedDistributionCopyWith<$Res> { + factory $EncryptedDistributionCopyWith(EncryptedDistribution value, + $Res Function(EncryptedDistribution) then) = + _$EncryptedDistributionCopyWithImpl<$Res, EncryptedDistribution>; + @useResult + $Res call( + {String recipientId, + @BlobConverter() Blob ephemeralPub, + @BlobConverter() Blob iv, + @BlobConverter() Blob ciphertext}); +} + +/// @nodoc +class _$EncryptedDistributionCopyWithImpl<$Res, + $Val extends EncryptedDistribution> + implements $EncryptedDistributionCopyWith<$Res> { + _$EncryptedDistributionCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of EncryptedDistribution + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? recipientId = null, + Object? ephemeralPub = null, + Object? iv = null, + Object? ciphertext = null, + }) { + return _then(_value.copyWith( + recipientId: null == recipientId + ? _value.recipientId + : recipientId // ignore: cast_nullable_to_non_nullable + as String, + ephemeralPub: null == ephemeralPub + ? _value.ephemeralPub + : ephemeralPub // ignore: cast_nullable_to_non_nullable + as Blob, + iv: null == iv + ? _value.iv + : iv // ignore: cast_nullable_to_non_nullable + as Blob, + ciphertext: null == ciphertext + ? _value.ciphertext + : ciphertext // ignore: cast_nullable_to_non_nullable + as Blob, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$EncryptedDistributionImplCopyWith<$Res> + implements $EncryptedDistributionCopyWith<$Res> { + factory _$$EncryptedDistributionImplCopyWith( + _$EncryptedDistributionImpl value, + $Res Function(_$EncryptedDistributionImpl) then) = + __$$EncryptedDistributionImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String recipientId, + @BlobConverter() Blob ephemeralPub, + @BlobConverter() Blob iv, + @BlobConverter() Blob ciphertext}); +} + +/// @nodoc +class __$$EncryptedDistributionImplCopyWithImpl<$Res> + extends _$EncryptedDistributionCopyWithImpl<$Res, + _$EncryptedDistributionImpl> + implements _$$EncryptedDistributionImplCopyWith<$Res> { + __$$EncryptedDistributionImplCopyWithImpl(_$EncryptedDistributionImpl _value, + $Res Function(_$EncryptedDistributionImpl) _then) + : super(_value, _then); + + /// Create a copy of EncryptedDistribution + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? recipientId = null, + Object? ephemeralPub = null, + Object? iv = null, + Object? ciphertext = null, + }) { + return _then(_$EncryptedDistributionImpl( + recipientId: null == recipientId + ? _value.recipientId + : recipientId // ignore: cast_nullable_to_non_nullable + as String, + ephemeralPub: null == ephemeralPub + ? _value.ephemeralPub + : ephemeralPub // ignore: cast_nullable_to_non_nullable + as Blob, + iv: null == iv + ? _value.iv + : iv // ignore: cast_nullable_to_non_nullable + as Blob, + ciphertext: null == ciphertext + ? _value.ciphertext + : ciphertext // ignore: cast_nullable_to_non_nullable + as Blob, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$EncryptedDistributionImpl extends _EncryptedDistribution { + const _$EncryptedDistributionImpl( + {this.recipientId = "", + @BlobConverter() required this.ephemeralPub, + @BlobConverter() required this.iv, + @BlobConverter() required this.ciphertext}) + : super._(); + + factory _$EncryptedDistributionImpl.fromJson(Map json) => + _$$EncryptedDistributionImplFromJson(json); + + @override + @JsonKey() + final String recipientId; + @override + @BlobConverter() + final Blob ephemeralPub; + @override + @BlobConverter() + final Blob iv; + @override + @BlobConverter() + final Blob ciphertext; + + @override + String toString() { + return 'EncryptedDistribution(recipientId: $recipientId, ephemeralPub: $ephemeralPub, iv: $iv, ciphertext: $ciphertext)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$EncryptedDistributionImpl && + (identical(other.recipientId, recipientId) || + other.recipientId == recipientId) && + (identical(other.ephemeralPub, ephemeralPub) || + other.ephemeralPub == ephemeralPub) && + (identical(other.iv, iv) || other.iv == iv) && + (identical(other.ciphertext, ciphertext) || + other.ciphertext == ciphertext)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => + Object.hash(runtimeType, recipientId, ephemeralPub, iv, ciphertext); + + /// Create a copy of EncryptedDistribution + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$EncryptedDistributionImplCopyWith<_$EncryptedDistributionImpl> + get copyWith => __$$EncryptedDistributionImplCopyWithImpl< + _$EncryptedDistributionImpl>(this, _$identity); + + @override + Map toJson() { + return _$$EncryptedDistributionImplToJson( + this, + ); + } +} + +abstract class _EncryptedDistribution extends EncryptedDistribution { + const factory _EncryptedDistribution( + {final String recipientId, + @BlobConverter() required final Blob ephemeralPub, + @BlobConverter() required final Blob iv, + @BlobConverter() required final Blob ciphertext}) = + _$EncryptedDistributionImpl; + const _EncryptedDistribution._() : super._(); + + factory _EncryptedDistribution.fromJson(Map json) = + _$EncryptedDistributionImpl.fromJson; + + @override + String get recipientId; + @override + @BlobConverter() + Blob get ephemeralPub; + @override + @BlobConverter() + Blob get iv; + @override + @BlobConverter() + Blob get ciphertext; + + /// Create a copy of EncryptedDistribution + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$EncryptedDistributionImplCopyWith<_$EncryptedDistributionImpl> + get copyWith => throw _privateConstructorUsedError; +} + +ApiSenderKeyRecord _$ApiSenderKeyRecordFromJson(Map json) { + return _ApiSenderKeyRecord.fromJson(json); +} + +/// @nodoc +mixin _$ApiSenderKeyRecord { + String get id => throw _privateConstructorUsedError; + int get device_id => throw _privateConstructorUsedError; + String get distribution_id => throw _privateConstructorUsedError; + @BlobConverter() + Blob get record => throw _privateConstructorUsedError; + String get address => throw _privateConstructorUsedError; + int get created_at => throw _privateConstructorUsedError; + + /// Serializes this ApiSenderKeyRecord to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ApiSenderKeyRecord + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ApiSenderKeyRecordCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ApiSenderKeyRecordCopyWith<$Res> { + factory $ApiSenderKeyRecordCopyWith( + ApiSenderKeyRecord value, $Res Function(ApiSenderKeyRecord) then) = + _$ApiSenderKeyRecordCopyWithImpl<$Res, ApiSenderKeyRecord>; + @useResult + $Res call( + {String id, + int device_id, + String distribution_id, + @BlobConverter() Blob record, + String address, + int created_at}); +} + +/// @nodoc +class _$ApiSenderKeyRecordCopyWithImpl<$Res, $Val extends ApiSenderKeyRecord> + implements $ApiSenderKeyRecordCopyWith<$Res> { + _$ApiSenderKeyRecordCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ApiSenderKeyRecord + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? device_id = null, + Object? distribution_id = null, + Object? record = null, + Object? address = null, + Object? created_at = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + device_id: null == device_id + ? _value.device_id + : device_id // ignore: cast_nullable_to_non_nullable + as int, + distribution_id: null == distribution_id + ? _value.distribution_id + : distribution_id // ignore: cast_nullable_to_non_nullable + as String, + record: null == record + ? _value.record + : record // ignore: cast_nullable_to_non_nullable + as Blob, + address: null == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String, + created_at: null == created_at + ? _value.created_at + : created_at // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ApiSenderKeyRecordImplCopyWith<$Res> + implements $ApiSenderKeyRecordCopyWith<$Res> { + factory _$$ApiSenderKeyRecordImplCopyWith(_$ApiSenderKeyRecordImpl value, + $Res Function(_$ApiSenderKeyRecordImpl) then) = + __$$ApiSenderKeyRecordImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String id, + int device_id, + String distribution_id, + @BlobConverter() Blob record, + String address, + int created_at}); +} + +/// @nodoc +class __$$ApiSenderKeyRecordImplCopyWithImpl<$Res> + extends _$ApiSenderKeyRecordCopyWithImpl<$Res, _$ApiSenderKeyRecordImpl> + implements _$$ApiSenderKeyRecordImplCopyWith<$Res> { + __$$ApiSenderKeyRecordImplCopyWithImpl(_$ApiSenderKeyRecordImpl _value, + $Res Function(_$ApiSenderKeyRecordImpl) _then) + : super(_value, _then); + + /// Create a copy of ApiSenderKeyRecord + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? device_id = null, + Object? distribution_id = null, + Object? record = null, + Object? address = null, + Object? created_at = null, + }) { + return _then(_$ApiSenderKeyRecordImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + device_id: null == device_id + ? _value.device_id + : device_id // ignore: cast_nullable_to_non_nullable + as int, + distribution_id: null == distribution_id + ? _value.distribution_id + : distribution_id // ignore: cast_nullable_to_non_nullable + as String, + record: null == record + ? _value.record + : record // ignore: cast_nullable_to_non_nullable + as Blob, + address: null == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String, + created_at: null == created_at + ? _value.created_at + : created_at // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ApiSenderKeyRecordImpl extends _ApiSenderKeyRecord { + const _$ApiSenderKeyRecordImpl( + {required this.id, + required this.device_id, + required this.distribution_id, + @BlobConverter() required this.record, + this.address = '', + required this.created_at}) + : super._(); + + factory _$ApiSenderKeyRecordImpl.fromJson(Map json) => + _$$ApiSenderKeyRecordImplFromJson(json); + + @override + final String id; + @override + final int device_id; + @override + final String distribution_id; + @override + @BlobConverter() + final Blob record; + @override + @JsonKey() + final String address; + @override + final int created_at; + + @override + String toString() { + return 'ApiSenderKeyRecord(id: $id, device_id: $device_id, distribution_id: $distribution_id, record: $record, address: $address, created_at: $created_at)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ApiSenderKeyRecordImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.device_id, device_id) || + other.device_id == device_id) && + (identical(other.distribution_id, distribution_id) || + other.distribution_id == distribution_id) && + (identical(other.record, record) || other.record == record) && + (identical(other.address, address) || other.address == address) && + (identical(other.created_at, created_at) || + other.created_at == created_at)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, id, device_id, distribution_id, record, address, created_at); + + /// Create a copy of ApiSenderKeyRecord + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ApiSenderKeyRecordImplCopyWith<_$ApiSenderKeyRecordImpl> get copyWith => + __$$ApiSenderKeyRecordImplCopyWithImpl<_$ApiSenderKeyRecordImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ApiSenderKeyRecordImplToJson( + this, + ); + } +} + +abstract class _ApiSenderKeyRecord extends ApiSenderKeyRecord { + const factory _ApiSenderKeyRecord( + {required final String id, + required final int device_id, + required final String distribution_id, + @BlobConverter() required final Blob record, + final String address, + required final int created_at}) = _$ApiSenderKeyRecordImpl; + const _ApiSenderKeyRecord._() : super._(); + + factory _ApiSenderKeyRecord.fromJson(Map json) = + _$ApiSenderKeyRecordImpl.fromJson; + + @override + String get id; + @override + int get device_id; + @override + String get distribution_id; + @override + @BlobConverter() + Blob get record; + @override + String get address; + @override + int get created_at; + + /// Create a copy of ApiSenderKeyRecord + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ApiSenderKeyRecordImplCopyWith<_$ApiSenderKeyRecordImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/data/lib/api/space/api_group_key_model.g.dart b/data/lib/api/space/api_group_key_model.g.dart new file mode 100644 index 00000000..07e24758 --- /dev/null +++ b/data/lib/api/space/api_group_key_model.g.dart @@ -0,0 +1,84 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'api_group_key_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ApiGroupKeyImpl _$$ApiGroupKeyImplFromJson(Map json) => + _$ApiGroupKeyImpl( + doc_updated_at: (json['doc_updated_at'] as num).toInt(), + member_keys: (json['member_keys'] as Map?)?.map( + (k, e) => MapEntry( + k, ApiMemberKeyData.fromJson(e as Map)), + ) ?? + const {}, + ); + +Map _$$ApiGroupKeyImplToJson(_$ApiGroupKeyImpl instance) => + { + 'doc_updated_at': instance.doc_updated_at, + 'member_keys': + instance.member_keys.map((k, e) => MapEntry(k, e.toJson())), + }; + +_$ApiMemberKeyDataImpl _$$ApiMemberKeyDataImplFromJson( + Map json) => + _$ApiMemberKeyDataImpl( + member_device_id: (json['member_device_id'] as num?)?.toInt() ?? 0, + data_updated_at: (json['data_updated_at'] as num?)?.toInt() ?? 0, + distributions: (json['distributions'] as List?) + ?.map((e) => + EncryptedDistribution.fromJson(e as Map)) + .toList() ?? + const [], + ); + +Map _$$ApiMemberKeyDataImplToJson( + _$ApiMemberKeyDataImpl instance) => + { + 'member_device_id': instance.member_device_id, + 'data_updated_at': instance.data_updated_at, + 'distributions': instance.distributions.map((e) => e.toJson()).toList(), + }; + +_$EncryptedDistributionImpl _$$EncryptedDistributionImplFromJson( + Map json) => + _$EncryptedDistributionImpl( + recipientId: json['recipientId'] as String? ?? "", + ephemeralPub: const BlobConverter().fromJson(json['ephemeralPub']), + iv: const BlobConverter().fromJson(json['iv']), + ciphertext: const BlobConverter().fromJson(json['ciphertext']), + ); + +Map _$$EncryptedDistributionImplToJson( + _$EncryptedDistributionImpl instance) => + { + 'recipientId': instance.recipientId, + 'ephemeralPub': const BlobConverter().toJson(instance.ephemeralPub), + 'iv': const BlobConverter().toJson(instance.iv), + 'ciphertext': const BlobConverter().toJson(instance.ciphertext), + }; + +_$ApiSenderKeyRecordImpl _$$ApiSenderKeyRecordImplFromJson( + Map json) => + _$ApiSenderKeyRecordImpl( + id: json['id'] as String, + device_id: (json['device_id'] as num).toInt(), + distribution_id: json['distribution_id'] as String, + record: const BlobConverter().fromJson(json['record']), + address: json['address'] as String? ?? '', + created_at: (json['created_at'] as num).toInt(), + ); + +Map _$$ApiSenderKeyRecordImplToJson( + _$ApiSenderKeyRecordImpl instance) => + { + 'id': instance.id, + 'device_id': instance.device_id, + 'distribution_id': instance.distribution_id, + 'record': const BlobConverter().toJson(instance.record), + 'address': instance.address, + 'created_at': instance.created_at, + }; diff --git a/data/lib/api/space/api_sender_key_record.dart b/data/lib/api/space/api_sender_key_record.dart new file mode 100644 index 00000000..1b2bc113 --- /dev/null +++ b/data/lib/api/space/api_sender_key_record.dart @@ -0,0 +1,23 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import '../../converter/blob_converter.dart'; + +part 'api_sender_key_record.freezed.dart'; +part 'api_sender_key_record.g.dart'; + +@freezed +class ApiSenderKeyRecord with _$ApiSenderKeyRecord { + const ApiSenderKeyRecord._(); + + const factory ApiSenderKeyRecord({ + required String id, + @Default(0) int deviceId, + @Default('') String address, + @Default('') String distributionId, + required int created_at, + @BlobConverter() required Blob record, + }) = _ApiSenderKeyRecord; + + factory ApiSenderKeyRecord.fromJson(Map data) => + _$ApiSenderKeyRecordFromJson(data); +} diff --git a/data/lib/api/space/api_sender_key_record.freezed.dart b/data/lib/api/space/api_sender_key_record.freezed.dart new file mode 100644 index 00000000..9bd534e5 --- /dev/null +++ b/data/lib/api/space/api_sender_key_record.freezed.dart @@ -0,0 +1,281 @@ +// 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 'api_sender_key_record.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'); + +ApiSenderKeyRecord _$ApiSenderKeyRecordFromJson(Map json) { + return _ApiSenderKeyRecord.fromJson(json); +} + +/// @nodoc +mixin _$ApiSenderKeyRecord { + String get id => throw _privateConstructorUsedError; + int get deviceId => throw _privateConstructorUsedError; + String get address => throw _privateConstructorUsedError; + String get distributionId => throw _privateConstructorUsedError; + int get created_at => throw _privateConstructorUsedError; + @BlobConverter() + Blob get record => throw _privateConstructorUsedError; + + /// Serializes this ApiSenderKeyRecord to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ApiSenderKeyRecord + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ApiSenderKeyRecordCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ApiSenderKeyRecordCopyWith<$Res> { + factory $ApiSenderKeyRecordCopyWith( + ApiSenderKeyRecord value, $Res Function(ApiSenderKeyRecord) then) = + _$ApiSenderKeyRecordCopyWithImpl<$Res, ApiSenderKeyRecord>; + @useResult + $Res call( + {String id, + int deviceId, + String address, + String distributionId, + int created_at, + @BlobConverter() Blob record}); +} + +/// @nodoc +class _$ApiSenderKeyRecordCopyWithImpl<$Res, $Val extends ApiSenderKeyRecord> + implements $ApiSenderKeyRecordCopyWith<$Res> { + _$ApiSenderKeyRecordCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ApiSenderKeyRecord + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? deviceId = null, + Object? address = null, + Object? distributionId = null, + Object? created_at = null, + Object? record = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + deviceId: null == deviceId + ? _value.deviceId + : deviceId // ignore: cast_nullable_to_non_nullable + as int, + address: null == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String, + distributionId: null == distributionId + ? _value.distributionId + : distributionId // ignore: cast_nullable_to_non_nullable + as String, + created_at: null == created_at + ? _value.created_at + : created_at // ignore: cast_nullable_to_non_nullable + as int, + record: null == record + ? _value.record + : record // ignore: cast_nullable_to_non_nullable + as Blob, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ApiSenderKeyRecordImplCopyWith<$Res> + implements $ApiSenderKeyRecordCopyWith<$Res> { + factory _$$ApiSenderKeyRecordImplCopyWith(_$ApiSenderKeyRecordImpl value, + $Res Function(_$ApiSenderKeyRecordImpl) then) = + __$$ApiSenderKeyRecordImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String id, + int deviceId, + String address, + String distributionId, + int created_at, + @BlobConverter() Blob record}); +} + +/// @nodoc +class __$$ApiSenderKeyRecordImplCopyWithImpl<$Res> + extends _$ApiSenderKeyRecordCopyWithImpl<$Res, _$ApiSenderKeyRecordImpl> + implements _$$ApiSenderKeyRecordImplCopyWith<$Res> { + __$$ApiSenderKeyRecordImplCopyWithImpl(_$ApiSenderKeyRecordImpl _value, + $Res Function(_$ApiSenderKeyRecordImpl) _then) + : super(_value, _then); + + /// Create a copy of ApiSenderKeyRecord + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? deviceId = null, + Object? address = null, + Object? distributionId = null, + Object? created_at = null, + Object? record = null, + }) { + return _then(_$ApiSenderKeyRecordImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + deviceId: null == deviceId + ? _value.deviceId + : deviceId // ignore: cast_nullable_to_non_nullable + as int, + address: null == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String, + distributionId: null == distributionId + ? _value.distributionId + : distributionId // ignore: cast_nullable_to_non_nullable + as String, + created_at: null == created_at + ? _value.created_at + : created_at // ignore: cast_nullable_to_non_nullable + as int, + record: null == record + ? _value.record + : record // ignore: cast_nullable_to_non_nullable + as Blob, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ApiSenderKeyRecordImpl extends _ApiSenderKeyRecord { + const _$ApiSenderKeyRecordImpl( + {required this.id, + this.deviceId = 0, + this.address = '', + this.distributionId = '', + required this.created_at, + @BlobConverter() required this.record}) + : super._(); + + factory _$ApiSenderKeyRecordImpl.fromJson(Map json) => + _$$ApiSenderKeyRecordImplFromJson(json); + + @override + final String id; + @override + @JsonKey() + final int deviceId; + @override + @JsonKey() + final String address; + @override + @JsonKey() + final String distributionId; + @override + final int created_at; + @override + @BlobConverter() + final Blob record; + + @override + String toString() { + return 'ApiSenderKeyRecord(id: $id, deviceId: $deviceId, address: $address, distributionId: $distributionId, created_at: $created_at, record: $record)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ApiSenderKeyRecordImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.deviceId, deviceId) || + other.deviceId == deviceId) && + (identical(other.address, address) || other.address == address) && + (identical(other.distributionId, distributionId) || + other.distributionId == distributionId) && + (identical(other.created_at, created_at) || + other.created_at == created_at) && + (identical(other.record, record) || other.record == record)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, id, deviceId, address, distributionId, created_at, record); + + /// Create a copy of ApiSenderKeyRecord + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ApiSenderKeyRecordImplCopyWith<_$ApiSenderKeyRecordImpl> get copyWith => + __$$ApiSenderKeyRecordImplCopyWithImpl<_$ApiSenderKeyRecordImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ApiSenderKeyRecordImplToJson( + this, + ); + } +} + +abstract class _ApiSenderKeyRecord extends ApiSenderKeyRecord { + const factory _ApiSenderKeyRecord( + {required final String id, + final int deviceId, + final String address, + final String distributionId, + required final int created_at, + @BlobConverter() required final Blob record}) = _$ApiSenderKeyRecordImpl; + const _ApiSenderKeyRecord._() : super._(); + + factory _ApiSenderKeyRecord.fromJson(Map json) = + _$ApiSenderKeyRecordImpl.fromJson; + + @override + String get id; + @override + int get deviceId; + @override + String get address; + @override + String get distributionId; + @override + int get created_at; + @override + @BlobConverter() + Blob get record; + + /// Create a copy of ApiSenderKeyRecord + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ApiSenderKeyRecordImplCopyWith<_$ApiSenderKeyRecordImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/data/lib/api/space/api_sender_key_record.g.dart b/data/lib/api/space/api_sender_key_record.g.dart new file mode 100644 index 00000000..21940581 --- /dev/null +++ b/data/lib/api/space/api_sender_key_record.g.dart @@ -0,0 +1,29 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'api_sender_key_record.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ApiSenderKeyRecordImpl _$$ApiSenderKeyRecordImplFromJson( + Map json) => + _$ApiSenderKeyRecordImpl( + id: json['id'] as String, + deviceId: (json['deviceId'] as num?)?.toInt() ?? 0, + address: json['address'] as String? ?? '', + distributionId: json['distributionId'] as String? ?? '', + created_at: (json['created_at'] as num).toInt(), + record: const BlobConverter().fromJson(json['record']), + ); + +Map _$$ApiSenderKeyRecordImplToJson( + _$ApiSenderKeyRecordImpl instance) => + { + 'id': instance.id, + 'deviceId': instance.deviceId, + 'address': instance.address, + 'distributionId': instance.distributionId, + 'created_at': instance.created_at, + 'record': const BlobConverter().toJson(instance.record), + }; diff --git a/data/lib/api/space/api_space_service.dart b/data/lib/api/space/api_space_service.dart index 3ca26ad7..7ed2d2e6 100644 --- a/data/lib/api/space/api_space_service.dart +++ b/data/lib/api/space/api_space_service.dart @@ -1,25 +1,30 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/network/client.dart'; +import 'package:data/api/space/api_group_key_model.dart'; import 'package:data/api/space/space_models.dart'; -import 'package:data/storage/app_preferences.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:uuid/uuid.dart'; +import '../../utils/buffered_sender_keystore.dart'; +import '../../utils/distribution_key_generator.dart'; 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(bufferedSenderKeystoreProvider), )); class ApiSpaceService { final FirebaseFirestore _db; - final ApiUser? _currentUser; final ApiUserService userService; + final BufferedSenderKeystore bufferedSenderKeystore; - ApiSpaceService(this._db, this._currentUser, this.userService); + ApiSpaceService( + this._db, + this.userService, + this.bufferedSenderKeystore, + ); CollectionReference get _spaceRef => _db.collection("spaces").withConverter( @@ -33,16 +38,35 @@ class ApiSpaceService { .collection('space_members'); } - Future createSpace(String name) async { + DocumentReference spaceGroupKeysDocRef(String spaceId) { + return FirebaseFirestore.instance + .collection('spaces') + .doc(spaceId) + .collection('group_keys') + .doc('group_keys') + .withConverter( + fromFirestore: ApiGroupKey.fromFireStore, + toFirestore: (key, options) => key.toJson()); + } + + Future createSpace( + String name, + String adminId, + Blob? identityKeyPublic, + ) async { final doc = _spaceRef.doc(); - final adminId = _currentUser?.id ?? ""; final space = ApiSpace( id: doc.id, admin_id: adminId, name: name, created_at: DateTime.now().millisecondsSinceEpoch); await doc.set(space); - await joinSpace(doc.id, adminId); + + final emptyGroupKeys = + ApiGroupKey(doc_updated_at: DateTime.now().millisecondsSinceEpoch); + + await spaceGroupKeysDocRef(doc.id).set(emptyGroupKeys); + await joinSpace(doc.id, adminId, identityKeyPublic); return doc.id; } @@ -54,13 +78,14 @@ class ApiSpaceService { return null; } - Future joinSpace(String spaceId, String userId, + Future joinSpace(String spaceId, String userId, Blob? identityKeyPublic, {int role = SPACE_MEMBER_ROLE_MEMBER}) async { final member = ApiSpaceMember( space_id: spaceId, user_id: userId, role: role, + identity_key_public: identityKeyPublic, location_enabled: true, id: const Uuid().v4(), created_at: DateTime.now().millisecondsSinceEpoch, @@ -68,6 +93,8 @@ class ApiSpaceService { await spaceMemberRef(spaceId).doc(userId).set(member.toJson()); await userService.addSpaceId(userId, spaceId); + + await _distributeSenderKeyToSpaceMembers(spaceId, userId); } Future> getMembersBySpaceId(String spaceId) async { @@ -149,9 +176,53 @@ class ApiSpaceService { for (final doc in querySnapshot.docs) { await doc.reference.delete(); } + + final docRef = spaceGroupKeysDocRef(spaceId); + await docRef.update({ + "doc_updated_at": DateTime.now().millisecondsSinceEpoch, + "member_keys.$userId": FieldValue.delete() + }); } Future updateSpace(ApiSpace space) async { await _spaceRef.doc(space.id).set(space); } + + Future _distributeSenderKeyToSpaceMembers( + String spaceId, String userId) async { + final spaceMembers = await getMembersBySpaceId(spaceId); + final membersKeyData = await generateMemberKeyData(spaceId, + senderUserId: userId, + spaceMembers: spaceMembers, + bufferedSenderKeyStore: bufferedSenderKeystore); + + await _updateGroupKeys(spaceId, userId, membersKeyData); + } + + Future _updateGroupKeys( + String spaceId, String userId, ApiMemberKeyData membersKeyData) async { + await _db.runTransaction((transaction) async { + final groupKeysDocRef = spaceGroupKeysDocRef(spaceId); + final snapshot = await transaction.get(groupKeysDocRef); + + final updatedAt = DateTime.now().millisecondsSinceEpoch; + final data = snapshot.data() ?? ApiGroupKey(doc_updated_at: updatedAt); + + final oldMemberKeyData = + data.member_keys[userId] ?? const ApiMemberKeyData(); + + final newMemberKeyData = oldMemberKeyData.copyWith( + member_device_id: membersKeyData.member_device_id, + data_updated_at: updatedAt, + distributions: membersKeyData.distributions, + ); + + final updates = { + 'member_keys.$userId': newMemberKeyData.toJson(), + 'doc_updated_at': DateTime.now().millisecondsSinceEpoch, + }; + + transaction.update(groupKeysDocRef, updates); + }); + } } diff --git a/data/lib/api/space/space_models.dart b/data/lib/api/space/space_models.dart index dfe6553f..3e76d748 100644 --- a/data/lib/api/space/space_models.dart +++ b/data/lib/api/space/space_models.dart @@ -2,8 +2,8 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/auth/auth_models.dart'; +import 'package:data/converter/blob_converter.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; - part 'space_models.freezed.dart'; part 'space_models.g.dart'; @@ -41,6 +41,7 @@ class ApiSpaceMember with _$ApiSpaceMember { required String user_id, required int role, required bool location_enabled, + @BlobConverter() Blob? identity_key_public, int? created_at, }) = _ApiSpaceMember; diff --git a/data/lib/api/space/space_models.freezed.dart b/data/lib/api/space/space_models.freezed.dart index 0b2670d9..0bd7d756 100644 --- a/data/lib/api/space/space_models.freezed.dart +++ b/data/lib/api/space/space_models.freezed.dart @@ -25,8 +25,12 @@ mixin _$ApiSpace { String get name => throw _privateConstructorUsedError; int? get created_at => throw _privateConstructorUsedError; + /// Serializes this ApiSpace to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiSpace + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiSpaceCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -49,6 +53,8 @@ class _$ApiSpaceCopyWithImpl<$Res, $Val extends ApiSpace> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiSpace + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -97,6 +103,8 @@ class __$$ApiSpaceImplCopyWithImpl<$Res> _$ApiSpaceImpl _value, $Res Function(_$ApiSpaceImpl) _then) : super(_value, _then); + /// Create a copy of ApiSpace + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -166,11 +174,13 @@ class _$ApiSpaceImpl extends _ApiSpace { other.created_at == created_at)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash(runtimeType, id, admin_id, name, created_at); - @JsonKey(ignore: true) + /// Create a copy of ApiSpace + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiSpaceImplCopyWith<_$ApiSpaceImpl> get copyWith => @@ -203,8 +213,11 @@ abstract class _ApiSpace extends ApiSpace { String get name; @override int? get created_at; + + /// Create a copy of ApiSpace + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiSpaceImplCopyWith<_$ApiSpaceImpl> get copyWith => throw _privateConstructorUsedError; } @@ -220,10 +233,16 @@ mixin _$ApiSpaceMember { String get user_id => throw _privateConstructorUsedError; int get role => throw _privateConstructorUsedError; bool get location_enabled => throw _privateConstructorUsedError; + @BlobConverter() + Blob? get identity_key_public => throw _privateConstructorUsedError; int? get created_at => throw _privateConstructorUsedError; + /// Serializes this ApiSpaceMember to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiSpaceMember + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiSpaceMemberCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -240,6 +259,7 @@ abstract class $ApiSpaceMemberCopyWith<$Res> { String user_id, int role, bool location_enabled, + @BlobConverter() Blob? identity_key_public, int? created_at}); } @@ -253,6 +273,8 @@ class _$ApiSpaceMemberCopyWithImpl<$Res, $Val extends ApiSpaceMember> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiSpaceMember + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -261,6 +283,7 @@ class _$ApiSpaceMemberCopyWithImpl<$Res, $Val extends ApiSpaceMember> Object? user_id = null, Object? role = null, Object? location_enabled = null, + Object? identity_key_public = freezed, Object? created_at = freezed, }) { return _then(_value.copyWith( @@ -284,6 +307,10 @@ class _$ApiSpaceMemberCopyWithImpl<$Res, $Val extends ApiSpaceMember> ? _value.location_enabled : location_enabled // ignore: cast_nullable_to_non_nullable as bool, + identity_key_public: freezed == identity_key_public + ? _value.identity_key_public + : identity_key_public // ignore: cast_nullable_to_non_nullable + as Blob?, created_at: freezed == created_at ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable @@ -306,6 +333,7 @@ abstract class _$$ApiSpaceMemberImplCopyWith<$Res> String user_id, int role, bool location_enabled, + @BlobConverter() Blob? identity_key_public, int? created_at}); } @@ -317,6 +345,8 @@ class __$$ApiSpaceMemberImplCopyWithImpl<$Res> _$ApiSpaceMemberImpl _value, $Res Function(_$ApiSpaceMemberImpl) _then) : super(_value, _then); + /// Create a copy of ApiSpaceMember + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -325,6 +355,7 @@ class __$$ApiSpaceMemberImplCopyWithImpl<$Res> Object? user_id = null, Object? role = null, Object? location_enabled = null, + Object? identity_key_public = freezed, Object? created_at = freezed, }) { return _then(_$ApiSpaceMemberImpl( @@ -348,6 +379,10 @@ class __$$ApiSpaceMemberImplCopyWithImpl<$Res> ? _value.location_enabled : location_enabled // ignore: cast_nullable_to_non_nullable as bool, + identity_key_public: freezed == identity_key_public + ? _value.identity_key_public + : identity_key_public // ignore: cast_nullable_to_non_nullable + as Blob?, created_at: freezed == created_at ? _value.created_at : created_at // ignore: cast_nullable_to_non_nullable @@ -365,6 +400,7 @@ class _$ApiSpaceMemberImpl extends _ApiSpaceMember { required this.user_id, required this.role, required this.location_enabled, + @BlobConverter() this.identity_key_public, this.created_at}) : super._(); @@ -382,11 +418,14 @@ class _$ApiSpaceMemberImpl extends _ApiSpaceMember { @override final bool location_enabled; @override + @BlobConverter() + final Blob? identity_key_public; + @override final int? created_at; @override String toString() { - return 'ApiSpaceMember(id: $id, space_id: $space_id, user_id: $user_id, role: $role, location_enabled: $location_enabled, created_at: $created_at)'; + return 'ApiSpaceMember(id: $id, space_id: $space_id, user_id: $user_id, role: $role, location_enabled: $location_enabled, identity_key_public: $identity_key_public, created_at: $created_at)'; } @override @@ -401,16 +440,20 @@ class _$ApiSpaceMemberImpl extends _ApiSpaceMember { (identical(other.role, role) || other.role == role) && (identical(other.location_enabled, location_enabled) || other.location_enabled == location_enabled) && + (identical(other.identity_key_public, identity_key_public) || + other.identity_key_public == identity_key_public) && (identical(other.created_at, created_at) || other.created_at == created_at)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash( - runtimeType, id, space_id, user_id, role, location_enabled, created_at); + int get hashCode => Object.hash(runtimeType, id, space_id, user_id, role, + location_enabled, identity_key_public, created_at); - @JsonKey(ignore: true) + /// Create a copy of ApiSpaceMember + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiSpaceMemberImplCopyWith<_$ApiSpaceMemberImpl> get copyWith => @@ -432,6 +475,7 @@ abstract class _ApiSpaceMember extends ApiSpaceMember { required final String user_id, required final int role, required final bool location_enabled, + @BlobConverter() final Blob? identity_key_public, final int? created_at}) = _$ApiSpaceMemberImpl; const _ApiSpaceMember._() : super._(); @@ -449,9 +493,15 @@ abstract class _ApiSpaceMember extends ApiSpaceMember { @override bool get location_enabled; @override + @BlobConverter() + Blob? get identity_key_public; + @override int? get created_at; + + /// Create a copy of ApiSpaceMember + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiSpaceMemberImplCopyWith<_$ApiSpaceMemberImpl> get copyWith => throw _privateConstructorUsedError; } @@ -467,8 +517,12 @@ mixin _$ApiSpaceInvitation { String get code => throw _privateConstructorUsedError; int? get created_at => throw _privateConstructorUsedError; + /// Serializes this ApiSpaceInvitation to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of ApiSpaceInvitation + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ApiSpaceInvitationCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -492,6 +546,8 @@ class _$ApiSpaceInvitationCopyWithImpl<$Res, $Val extends ApiSpaceInvitation> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ApiSpaceInvitation + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -540,6 +596,8 @@ class __$$ApiSpaceInvitationImplCopyWithImpl<$Res> $Res Function(_$ApiSpaceInvitationImpl) _then) : super(_value, _then); + /// Create a copy of ApiSpaceInvitation + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -609,11 +667,13 @@ class _$ApiSpaceInvitationImpl extends _ApiSpaceInvitation { other.created_at == created_at)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash(runtimeType, id, space_id, code, created_at); - @JsonKey(ignore: true) + /// Create a copy of ApiSpaceInvitation + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ApiSpaceInvitationImplCopyWith<_$ApiSpaceInvitationImpl> get copyWith => @@ -647,8 +707,11 @@ abstract class _ApiSpaceInvitation extends ApiSpaceInvitation { String get code; @override int? get created_at; + + /// Create a copy of ApiSpaceInvitation + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ApiSpaceInvitationImplCopyWith<_$ApiSpaceInvitationImpl> get copyWith => throw _privateConstructorUsedError; } @@ -662,8 +725,12 @@ mixin _$SpaceInfo { ApiSpace get space => throw _privateConstructorUsedError; List get members => throw _privateConstructorUsedError; + /// Serializes this SpaceInfo to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of SpaceInfo + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $SpaceInfoCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -688,6 +755,8 @@ class _$SpaceInfoCopyWithImpl<$Res, $Val extends SpaceInfo> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of SpaceInfo + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -706,6 +775,8 @@ class _$SpaceInfoCopyWithImpl<$Res, $Val extends SpaceInfo> ) as $Val); } + /// Create a copy of SpaceInfo + /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') $ApiSpaceCopyWith<$Res> get space { @@ -737,6 +808,8 @@ class __$$SpaceInfoImplCopyWithImpl<$Res> _$SpaceInfoImpl _value, $Res Function(_$SpaceInfoImpl) _then) : super(_value, _then); + /// Create a copy of SpaceInfo + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -791,12 +864,14 @@ class _$SpaceInfoImpl extends _SpaceInfo { const DeepCollectionEquality().equals(other._members, _members)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, space, const DeepCollectionEquality().hash(_members)); - @JsonKey(ignore: true) + /// Create a copy of SpaceInfo + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$SpaceInfoImplCopyWith<_$SpaceInfoImpl> get copyWith => @@ -823,8 +898,11 @@ abstract class _SpaceInfo extends SpaceInfo { ApiSpace get space; @override List get members; + + /// Create a copy of SpaceInfo + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$SpaceInfoImplCopyWith<_$SpaceInfoImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/data/lib/api/space/space_models.g.dart b/data/lib/api/space/space_models.g.dart index e83fb6ba..5a86fd5c 100644 --- a/data/lib/api/space/space_models.g.dart +++ b/data/lib/api/space/space_models.g.dart @@ -29,6 +29,8 @@ _$ApiSpaceMemberImpl _$$ApiSpaceMemberImplFromJson(Map json) => user_id: json['user_id'] as String, role: (json['role'] as num).toInt(), location_enabled: json['location_enabled'] as bool, + identity_key_public: + const BlobConverter().fromJson(json['identity_key_public']), created_at: (json['created_at'] as num?)?.toInt(), ); @@ -40,9 +42,17 @@ Map _$$ApiSpaceMemberImplToJson( 'user_id': instance.user_id, 'role': instance.role, 'location_enabled': instance.location_enabled, + 'identity_key_public': _$JsonConverterToJson( + instance.identity_key_public, const BlobConverter().toJson), 'created_at': instance.created_at, }; +Json? _$JsonConverterToJson( + Value? value, + Json? Function(Value value) toJson, +) => + value == null ? null : toJson(value); + _$ApiSpaceInvitationImpl _$$ApiSpaceInvitationImplFromJson( Map json) => _$ApiSpaceInvitationImpl( diff --git a/data/lib/api/subscription/subscription_models.freezed.dart b/data/lib/api/subscription/subscription_models.freezed.dart index 91042844..ea42d9bb 100644 --- a/data/lib/api/subscription/subscription_models.freezed.dart +++ b/data/lib/api/subscription/subscription_models.freezed.dart @@ -21,7 +21,9 @@ mixin _$SubscriptionPlan { String get planDetail => throw _privateConstructorUsedError; String get planInfo => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + /// Create a copy of SubscriptionPlan + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $SubscriptionPlanCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -45,6 +47,8 @@ class _$SubscriptionPlanCopyWithImpl<$Res, $Val extends SubscriptionPlan> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of SubscriptionPlan + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -93,6 +97,8 @@ class __$$SubscriptionPlanImplCopyWithImpl<$Res> $Res Function(_$SubscriptionPlanImpl) _then) : super(_value, _then); + /// Create a copy of SubscriptionPlan + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -161,7 +167,9 @@ class _$SubscriptionPlanImpl implements _SubscriptionPlan { @override int get hashCode => Object.hash(runtimeType, id, name, planDetail, planInfo); - @JsonKey(ignore: true) + /// Create a copy of SubscriptionPlan + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$SubscriptionPlanImplCopyWith<_$SubscriptionPlanImpl> get copyWith => @@ -184,8 +192,11 @@ abstract class _SubscriptionPlan implements SubscriptionPlan { String get planDetail; @override String get planInfo; + + /// Create a copy of SubscriptionPlan + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$SubscriptionPlanImplCopyWith<_$SubscriptionPlanImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/data/lib/converter/blob_converter.dart b/data/lib/converter/blob_converter.dart new file mode 100644 index 00000000..6d06f266 --- /dev/null +++ b/data/lib/converter/blob_converter.dart @@ -0,0 +1,35 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +class BlobConverter implements JsonConverter { + const BlobConverter(); + + @override + Blob fromJson(dynamic json) { + if (json is Blob) { + return json; + } + + if (json is Map && json.containsKey('_byteString')) { + final base64String = json['_byteString'] as String; + return Blob(base64Decode(base64String)); + } + + + if (json is List) { + return Blob(Uint8List.fromList(json.cast())); + } + + return Blob(Uint8List(0)); + } + + @override + dynamic toJson(Blob blob) { + return { + '_byteString': base64Encode(blob.bytes), + }; + } +} diff --git a/data/lib/domain/journey_lat_lng_entension.dart b/data/lib/domain/journey_lat_lng_entension.dart deleted file mode 100644 index 598057c8..00000000 --- a/data/lib/domain/journey_lat_lng_entension.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:google_maps_flutter/google_maps_flutter.dart'; - -import '../api/location/journey/journey.dart'; - -extension JourneyRouteLatLngExtension on JourneyRoute { - LatLng toLatLng() { - return LatLng(latitude, longitude); - } -} \ No newline at end of file diff --git a/data/lib/domain/location_data_extension.dart b/data/lib/domain/location_data_extension.dart deleted file mode 100644 index f60e1c1b..00000000 --- a/data/lib/domain/location_data_extension.dart +++ /dev/null @@ -1,17 +0,0 @@ -import '../api/location/journey/journey.dart'; -import '../api/location/location.dart'; - -extension LocationDataExtension on LocationData { - JourneyRoute toJourneyRoute() { - return JourneyRoute(latitude: latitude, longitude: longitude); - } - - ApiLocationJourney toLocationJourney(String userId, String journeyId) { - return ApiLocationJourney( - id: journeyId, - user_id: userId, - from_latitude: latitude, - from_longitude: longitude, - ); - } -} \ No newline at end of file diff --git a/data/lib/repository/journey_generator.dart b/data/lib/repository/journey_generator.dart index 7fc88663..5686e5e5 100644 --- a/data/lib/repository/journey_generator.dart +++ b/data/lib/repository/journey_generator.dart @@ -26,7 +26,7 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs from_longitude: newLocation.longitude, type: JOURNEY_TYPE_STEADY, created_at: DateTime.now().millisecondsSinceEpoch, - update_at: DateTime.now().millisecondsSinceEpoch, + updated_at: DateTime.now().millisecondsSinceEpoch, ) ); } @@ -45,7 +45,7 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs } final timeDifference = (newLocation.timestamp.millisecondsSinceEpoch) - - (lastKnownJourney.update_at ?? 0); + lastKnownJourney.updated_at; bool dayChanged = _isDayChanged(newLocation, lastKnownJourney); @@ -53,7 +53,7 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs final updateJourney = lastKnownJourney.copyWith( from_latitude: newLocation.latitude, from_longitude: newLocation.longitude, - update_at: DateTime.now().millisecondsSinceEpoch, + updated_at: DateTime.now().millisecondsSinceEpoch, ); return (updatedJourney: updateJourney, newJourney: null); } @@ -77,7 +77,7 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs final updatedJourney = lastKnownJourney.copyWith( from_latitude: newLocation.latitude, from_longitude: newLocation.longitude, - update_at: DateTime.now().millisecondsSinceEpoch, + updated_at: DateTime.now().millisecondsSinceEpoch, ); // create new moving journey @@ -91,7 +91,7 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs route_distance: distance, route_duration: timeDifference, created_at: DateTime.now().millisecondsSinceEpoch, - update_at: DateTime.now().millisecondsSinceEpoch, + updated_at: DateTime.now().millisecondsSinceEpoch, ); return (updatedJourney: updatedJourney, newJourney: newJourney); @@ -100,7 +100,7 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs final updateJourney = lastKnownJourney.copyWith( from_latitude: newLocation.latitude, from_longitude: newLocation.longitude, - update_at: DateTime.now().millisecondsSinceEpoch, + updated_at: DateTime.now().millisecondsSinceEpoch, ); return (updatedJourney: updateJourney, newJourney: null); } @@ -112,8 +112,8 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs to_latitude: newLocation.latitude, to_longitude: newLocation.longitude, route_distance: distance, - route_duration: (lastKnownJourney.update_at ?? 0) - - (lastKnownJourney.created_at ?? 0), + route_duration: + lastKnownJourney.updated_at - lastKnownJourney.created_at, routes: lastKnownJourney.routes + [ JourneyRoute( @@ -129,8 +129,8 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs from_latitude: newLocation.latitude, from_longitude: newLocation.longitude, type: JOURNEY_TYPE_STEADY, - created_at: lastKnownJourney.update_at ?? DateTime.now().millisecondsSinceEpoch, - update_at: DateTime.now().millisecondsSinceEpoch, + created_at: lastKnownJourney.updated_at, + updated_at: DateTime.now().millisecondsSinceEpoch, ); return (updatedJourney: updatedJourney, newJourney: newJourney); } else if (distance > MIN_DISTANCE_FOR_MOVING && @@ -140,8 +140,8 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs to_latitude: newLocation.latitude, to_longitude: newLocation.longitude, route_distance: distance + (lastKnownJourney.route_distance ?? 0), - route_duration: (lastKnownJourney.update_at ?? 0) - - (lastKnownJourney.created_at ?? 0), + route_duration: + lastKnownJourney.updated_at - lastKnownJourney.created_at, routes: lastKnownJourney.routes + [ JourneyRoute( @@ -149,7 +149,7 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs longitude: newLocation.longitude, ) ], - update_at: DateTime.now().millisecondsSinceEpoch, + updated_at: DateTime.now().millisecondsSinceEpoch, ); return (updatedJourney: updatedJourney, newJourney: null); @@ -161,8 +161,8 @@ const MIN_UPDATE_INTERVAL_MINUTE = 30000; // 30 secs bool _isDayChanged( LocationData? extractedLocation, ApiLocationJourney lastKnownJourney) { - DateTime lastKnownDate = DateTime.fromMillisecondsSinceEpoch( - lastKnownJourney.update_at ?? DateTime.now().millisecondsSinceEpoch); + DateTime lastKnownDate = + DateTime.fromMillisecondsSinceEpoch(lastKnownJourney.updated_at); int lastKnownDay = lastKnownDate.day; DateTime currentDate = extractedLocation != null diff --git a/data/lib/service/auth_service.dart b/data/lib/service/auth_service.dart index cad27c8f..d4031883 100644 --- a/data/lib/service/auth_service.dart +++ b/data/lib/service/auth_service.dart @@ -1,29 +1,44 @@ // ignore_for_file: constant_identifier_names +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_functions/cloud_functions.dart'; import 'package:data/api/auth/api_user_service.dart'; import 'package:data/api/auth/auth_models.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; - +import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; +import '../utils/private_key_helper.dart'; import '../log/logger.dart'; import '../storage/app_preferences.dart'; const NETWORK_STATUS_CHECK_INTERVAL = 5 * 60 * 1000; -final authServiceProvider = Provider((ref) => AuthService( - ref.read(currentUserPod), - ref.read(apiUserServiceProvider), - ref.read(currentUserJsonPod.notifier), - ref.read(currentUserSessionJsonPod.notifier))); +final authServiceProvider = Provider((ref) { + final provider = AuthService( + ref.read(currentUserPod), + ref.read(apiUserServiceProvider), + ref.read(currentUserJsonPod.notifier), + ref.read(currentUserSessionJsonPod.notifier), + ref.read(userPassKeyPod.notifier)); + + ref.listen(currentUserPod, (prev, user) { + provider._onUpdateUser(prevUser: prev, currentUser: user); + }); + + return provider; +}); class AuthService { - final ApiUser? _currentUser; + ApiUser? _currentUser; final ApiUserService userService; final StateController userJsonNotifier; final StateController userSessionJsonNotifier; + final StateController userPassKeyNotifier; AuthService(this._currentUser, this.userService, this.userJsonNotifier, - this.userSessionJsonNotifier); + this.userSessionJsonNotifier, this.userPassKeyNotifier); ApiUser? get currentUser => _currentUser; @@ -46,11 +61,36 @@ class AuthService { profileImage: profileImg, authType: authType, ); - userJsonNotifier.state = (data['user'] as ApiUser).toJsonString(); + _currentUser = data['user'] as ApiUser; + userJsonNotifier.state = _currentUser!.toJsonString(); userSessionJsonNotifier.state = (data['session'] as ApiSession).toJsonString(); - return data['isNewUser'] as bool; + final isNewUser = data['isNewUser'] as bool; + if (isNewUser) await generateAndSaveUserKeys("1111"); + return isNewUser; + } + + Future updateUserName( + {required String firstName, String? lastName}) async { + final user = + currentUser?.copyWith(first_name: firstName, last_name: lastName); + if (user == null) { + throw Exception("No user logged in"); + } + + await userService.updateUserName(user.id, + firstName: firstName, lastName: lastName); + + userJsonNotifier.state = user.toJsonString(); + } + + void saveUser(ApiUser? user) { + userJsonNotifier.state = user?.toJsonString(); + } + + void _onUpdateUser({ApiUser? prevUser, ApiUser? currentUser}) { + _currentUser = currentUser; } Future updateCurrentUser(ApiUser user) async { @@ -91,4 +131,45 @@ class AuthService { onStatusChecked(user); }); } + + Future generateAndSaveUserKeys(String passKey) async { + final user = currentUser; + if (user == null) { + throw Exception("No user logged in"); + } + + final updatedUser = await _generateAndSaveUserKeys(user, passKey); + userJsonNotifier.state = updatedUser.toJsonString(); + } + + Future _generateAndSaveUserKeys(ApiUser user, String passKey) async { + final identityKeyPair = generateIdentityKeyPair(); + final salt = Uint8List(16) + ..setAll(0, List.generate(16, (_) => Random().nextInt(256))); + final encryptedPrivateKey = await encryptPrivateKey( + identityKeyPair.getPrivateKey().serialize(), + passKey, + salt, + ); + + final publicKey = + Blob(identityKeyPair.getPublicKey().publicKey.serialize()); + final privateKey = Blob(encryptedPrivateKey); + final saltBlob = Blob(salt); + + // Store passkey in preferences + userPassKeyNotifier.state = passKey; + await userService.updateKeys( + user.id, + publicKey, + privateKey, + saltBlob, + ); + + return user.copyWith( + identity_key_public: publicKey, + identity_key_private: privateKey, + identity_key_salt: saltBlob, + ); + } } diff --git a/data/lib/service/space_service.dart b/data/lib/service/space_service.dart index 07d58927..30352e00 100644 --- a/data/lib/service/space_service.dart +++ b/data/lib/service/space_service.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:data/api/auth/api_user_service.dart'; import 'package:data/api/space/api_space_invitation_service.dart'; import 'package:data/api/space/api_space_service.dart'; @@ -13,18 +14,25 @@ import '../api/place/api_place.dart'; import '../storage/app_preferences.dart'; import 'location_service.dart'; -final spaceServiceProvider = Provider((ref) => SpaceService( +final spaceServiceProvider = Provider((ref) { + final provider = SpaceService( ref.read(currentUserPod), ref.read(apiSpaceServiceProvider), ref.read(apiSpaceInvitationServiceProvider), ref.read(currentSpaceId.notifier), ref.read(apiUserServiceProvider), ref.read(locationServiceProvider), - ref.read(placeServiceProvider), - )); + ref.read(placeServiceProvider)); + + ref.listen(currentUserPod, (prev, user) { + provider._onUpdateUser(prevUser: prev, currentUser: user); + }); + + return provider; +}); class SpaceService { - final ApiUser? currentUser; + ApiUser? _currentUser; final ApiSpaceService spaceService; final ApiSpaceInvitationService spaceInvitationService; final StateController _currentSpaceIdController; @@ -33,7 +41,7 @@ class SpaceService { final PlaceService placeService; SpaceService( - this.currentUser, + this._currentUser, this.spaceService, this.spaceInvitationService, this._currentSpaceIdController, @@ -48,18 +56,30 @@ class SpaceService { _currentSpaceIdController.state = value; } - Future createSpaceAndGetInviteCode(String spaceName) async { - final spaceId = await spaceService.createSpace(spaceName); + void _onUpdateUser({ApiUser? prevUser, ApiUser? currentUser}) { + _currentUser = currentUser; + } + + Future createSpaceAndGetInviteCode({ + required String spaceName, + required String userId, + required Blob? identityKeyPublic, + }) async { + final spaceId = + await spaceService.createSpace(spaceName, userId, identityKeyPublic); final generatedCode = await spaceInvitationService.createInvitation(spaceId); currentSpaceId = spaceId; return generatedCode; } - Future joinSpace(String spaceId, String userId) async { - await spaceService.joinSpace(spaceId, userId); + Future joinSpace(String spaceId) async { + final user = _currentUser; + if (user == null) return; + + await spaceService.joinSpace(spaceId, user.id, user.identity_key_public); await placeService.joinUserToExistingPlaces( - userId: userId, spaceId: spaceId); + userId: user.id, spaceId: spaceId); currentSpaceId = spaceId; } diff --git a/data/lib/storage/app_preferences.dart b/data/lib/storage/app_preferences.dart index 328440eb..5c94f47c 100644 --- a/data/lib/storage/app_preferences.dart +++ b/data/lib/storage/app_preferences.dart @@ -1,10 +1,10 @@ import 'dart:convert'; - import 'package:data/storage/preferences_provider.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:uuid/uuid.dart'; import '../api/auth/auth_models.dart'; +import '../api/space/api_group_key_model.dart'; final isIntroScreenShownPod = createPrefProvider( prefKey: "show_intro_screen", @@ -57,4 +57,19 @@ final currentSpaceId = createPrefProvider( final lastBatteryDialogPod = createPrefProvider( prefKey: 'show_battery_dialog', defaultValue: null, -); \ No newline at end of file +); + +final userPassKeyPod = createPrefProvider( + prefKey: "user_passkey", + defaultValue: null, +); + +final senderKeyJsonPod = createPrefProvider( + prefKey: "sender_key", + defaultValue: null, +); + +final senderKeyPod = Provider((ref) { + final json = ref.watch(senderKeyJsonPod); + return json == null ? null : ApiSenderKeyRecord.fromJson(jsonDecode(json)); +}); diff --git a/data/lib/utils/buffered_sender_keystore.dart b/data/lib/utils/buffered_sender_keystore.dart new file mode 100644 index 00000000..3cb4d4d3 --- /dev/null +++ b/data/lib/utils/buffered_sender_keystore.dart @@ -0,0 +1,161 @@ +import 'dart:convert'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:data/api/auth/auth_models.dart'; +import 'package:data/api/space/api_space_service.dart'; +import 'package:data/log/logger.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; + +import '../api/network/client.dart'; +import '../api/space/api_group_key_model.dart'; +import '../storage/app_preferences.dart'; + +final bufferedSenderKeystoreProvider = Provider((ref) => BufferedSenderKeystore( + ref.read(firestoreProvider), + ref.read(senderKeyJsonPod.notifier), + ref.read(currentUserJsonPod.notifier), + )); + +class StoreKey { + final SignalProtocolAddress address; + final String groupId; + final int senderDeviceId; + + StoreKey(this.address, this.groupId, this.senderDeviceId); +} + +class BufferedSenderKeystore extends SenderKeyStore { + final StateController senderKeyJsonState; + final StateController userJsonState; + final FirebaseFirestore _db; + + BufferedSenderKeystore(this._db, this.senderKeyJsonState, this.userJsonState); + + final Map _inMemoryStore = {}; + + CollectionReference senderKeyRef( + String spaceId, String userId) { + return _db + .collection('spaces') + .doc(spaceId) + .collection('space_members') + .doc(userId) + .collection('sender_key_record') + .withConverter( + fromFirestore: ApiSenderKeyRecord.fromFireStore, + toFirestore: (senderKey, options) => senderKey.toJson()); + } + + ApiUser? get currentUser => userJsonState.state == null + ? ApiUser.fromJson(jsonDecode(userJsonState.state ?? '')) + : null; + + @override + Future loadSenderKey(SenderKeyName senderKeyName) { + final sender = senderKeyName.sender; + final key = StoreKey(sender, senderKeyName.groupId, sender.getDeviceId()); + + final cache = _inMemoryStore[key]; + + final stateFromPref = senderKeyJsonState.state; + final cacheSenderKey = stateFromPref == null + ? null + : ApiSenderKeyRecord.fromJson(jsonDecode(stateFromPref)); + + final keyRecordFuture = cache != null + ? Future.value(cache) + : (cacheSenderKey != null + ? Future.value( + SenderKeyRecord.fromSerialized(cacheSenderKey.record.bytes)) + : null) ?? + fetchSenderKeyFromServer(sender); + + keyRecordFuture.then((keyRecord) { + _inMemoryStore[key] = keyRecord; + }); + + return keyRecordFuture; + } + + @override + Future storeSenderKey( + SenderKeyName senderKeyName, SenderKeyRecord record) { + final sender = senderKeyName.sender; + final key = StoreKey(sender, senderKeyName.groupId, sender.getDeviceId()); + if (_inMemoryStore.containsKey(key)) { + return Future.value(); + } + + _inMemoryStore[key] = record; + + saveSenderKeyToServer(senderKeyName, record).then((value) { + if (value != null) { + senderKeyJsonState.state = jsonEncode(value.toJson()); + } + }); + + return Future.value(); + } + + Future fetchSenderKeyFromServer( + SignalProtocolAddress sender) { + final newKeyRecord = SenderKeyRecord(); + final currentUser = this.currentUser; + if (currentUser == null) { + return Future.value(newKeyRecord); + } + + return senderKeyRef(sender.getName(), currentUser.id) + .where('device_id', isEqualTo: sender.getDeviceId()) + .get() + .then((querySnapshot) { + final doc = querySnapshot.docs.firstOrNull; + if (doc == null) { + return newKeyRecord; + } + + final apiSenderKeyRecord = doc.data(); + try { + return SenderKeyRecord.fromSerialized(apiSenderKeyRecord.record.bytes); + } catch (e, s) { + logger.e("Failed to deserialize sender key record", + error: e, stackTrace: s); + return newKeyRecord; + } + }).catchError((e, s) { + logger.e("Failed to fetch sender key from server for sender: $sender", + error: e, stackTrace: s); + return newKeyRecord; + }); + } + + Future saveSenderKeyToServer( + SenderKeyName senderKeyName, SenderKeyRecord record) async { + try { + final currentUser = this.currentUser; + if (currentUser == null) { + return null; + } + + final distributionId = senderKeyName.groupId; + final deviceId = senderKeyName.sender.getDeviceId(); + final uniqueDocId = "$deviceId-$distributionId"; + final senderKeyRecord = ApiSenderKeyRecord( + id: uniqueDocId, + device_id: deviceId, + distribution_id: distributionId, + record: Blob(record.serialize()), + created_at: DateTime.now().millisecondsSinceEpoch); + + await senderKeyRef(senderKeyRecord.distribution_id, currentUser.id) + .doc(uniqueDocId) + .set(senderKeyRecord); + + return senderKeyRecord; + } catch (e, s) { + logger.d("Failed to save sender key to server", error: e, stackTrace: s); + return null; + } + } +} diff --git a/data/lib/utils/distribution_key_generator.dart b/data/lib/utils/distribution_key_generator.dart new file mode 100644 index 00000000..5dc7f836 --- /dev/null +++ b/data/lib/utils/distribution_key_generator.dart @@ -0,0 +1,56 @@ +import 'dart:math'; + +import 'package:data/log/logger.dart'; +import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; + +import '../api/space/api_group_key_model.dart'; +import '../api/space/space_models.dart'; +import 'buffered_sender_keystore.dart'; +import 'ephemeral_distribution_helper.dart'; + +Future generateMemberKeyData(String spaceId, + {required String senderUserId, + required List spaceMembers, + required BufferedSenderKeystore bufferedSenderKeyStore}) async { + final deviceId = Random.secure().nextInt(0x7FFFFFFF); + final groupAddress = SignalProtocolAddress(spaceId, deviceId); + final sessionBuilder = GroupSessionBuilder(bufferedSenderKeyStore); + final senderKey = SenderKeyName(Random().nextInt(0x7FFFFFFF).toString(), groupAddress); + + final distributionMessage = await sessionBuilder.create(senderKey); + final distributionBytes = distributionMessage.serialize(); + + final List distributions = []; + + for (final member in spaceMembers) { + final publicBlob = member.identity_key_public; + + if (publicBlob == null) continue; + + try { + final publicKeyBytes = publicBlob.bytes; + if (publicKeyBytes.length != 33) { + logger.e("Invalid public key size for member ${member.user_id}"); + continue; + } + + final publicKey = Curve.decodePoint(publicKeyBytes, 0); + + final encryptedDistribution = await EphemeralECDHUtils.encrypt( + member.user_id, + distributionBytes, + publicKey, + ); + distributions.add(encryptedDistribution); + } catch (e) { + logger.e("Failed to decode public key for member ${member.user_id}: $e"); + continue; + } + } + + + return ApiMemberKeyData( + data_updated_at: DateTime.now().millisecondsSinceEpoch, + member_device_id: deviceId, + distributions: distributions); +} diff --git a/data/lib/utils/ephemeral_distribution_helper.dart b/data/lib/utils/ephemeral_distribution_helper.dart new file mode 100644 index 00000000..cfd62407 --- /dev/null +++ b/data/lib/utils/ephemeral_distribution_helper.dart @@ -0,0 +1,88 @@ +import 'dart:convert'; +import 'dart:typed_data'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:cryptography/cryptography.dart'; +import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; + +import '../api/space/api_group_key_model.dart'; + +class EphemeralECDHUtils { + static const int syntheticIvLength = 16; // Length of the synthetic initialization vector (IV). + + /// Encrypts the provided plaintext for a specific recipient using their public key. + static Future encrypt( + String receiverId, + Uint8List plaintext, + ECPublicKey receiverPub, + ) async { + final ephemeralPubKey = Curve.generateKeyPair(); + final ephemeralPrivateKeyBytes = ephemeralPubKey.privateKey; + final masterSecret = + Curve.calculateAgreement(receiverPub, ephemeralPrivateKeyBytes); + + // Compute synthetic IV + final syntheticIv = await _computeSyntheticIv(SecretKey(masterSecret), plaintext); + + // Compute cipher key + final cipherKey = await _computeCipherKey(SecretKey(masterSecret), syntheticIv); + + // Encrypt plaintext + final algorithm = AesCtr.with128bits(macAlgorithm: MacAlgorithm.empty); + final secretKey = SecretKey(cipherKey); + final secretBox = await algorithm.encrypt( + plaintext, + secretKey: secretKey, + nonce: syntheticIv, + ); + + final ciphertext = Uint8List.fromList(secretBox.cipherText); + return EncryptedDistribution( + recipientId: receiverId, + ephemeralPub: Blob(ephemeralPubKey.publicKey.serialize()), + iv: Blob(Uint8List.fromList(syntheticIv)), + ciphertext: Blob(ciphertext), + ); + + } + + /// Computes a synthetic IV using the master secret and plaintext. + static Future _computeSyntheticIv( + SecretKey sharedSecret, + Uint8List plaintext, + ) async { + final mac = Hmac.sha256(); + + // Derive synthetic IV key + final syntheticIvKey = await mac.calculateMac( + utf8.encode("auth"), + secretKey: sharedSecret, + ); + + // Compute synthetic IV + final syntheticIv = await mac.calculateMac( + plaintext, + secretKey: SecretKey(syntheticIvKey.bytes), + ); + + return Uint8List.fromList(syntheticIv.bytes.sublist(0, syntheticIvLength)); + } + + static Future _computeCipherKey( + SecretKey masterSecret, + Uint8List syntheticIv, + ) async { + final mac = Hmac.sha256(); + + // Derive cipher key + final cipherKeyMaterial = await mac.calculateMac( + utf8.encode("cipher"), + secretKey: masterSecret, + ); + final cipherKey = await mac.calculateMac( + syntheticIv, + secretKey: SecretKey(cipherKeyMaterial.bytes), + ); + + return Uint8List.fromList(cipherKey.bytes.sublist(0, syntheticIvLength)); // TODO check if this is correct, getting 32 instead of 16 + } +} diff --git a/data/lib/utils/private_key_helper.dart b/data/lib/utils/private_key_helper.dart new file mode 100644 index 00000000..eb940306 --- /dev/null +++ b/data/lib/utils/private_key_helper.dart @@ -0,0 +1,59 @@ +// ignore_for_file: constant_identifier_names + +import 'package:cryptography/cryptography.dart'; +import 'dart:typed_data'; + +class EncryptionException implements Exception { + final String message; + final dynamic cause; + + EncryptionException(this.message, [this.cause]); +} + +const int KEY_SIZE = 256; // bits +const int ITERATION_COUNT = 100000; +const int GCM_IV_SIZE = 12; // bytes +const int GCM_TAG_SIZE = 128; // bits + +/// Derives a SecretKey from the user's passkey/PIN using PBKDF2. +Future _deriveKeyFromPasskey(String passkey, Uint8List salt) async { + try { + final pbkdf2 = Pbkdf2( + macAlgorithm: Hmac.sha256(), + iterations: ITERATION_COUNT, + bits: KEY_SIZE, // 256 bits = 32 bytes output + ); + + final newSecretKey = await pbkdf2.deriveKeyFromPassword( + password: passkey, + nonce: salt, + ); + return newSecretKey; + } catch (e) { + throw EncryptionException('Key derivation failed', e); + } +} + +// Encrypt data using AES-GCM with the provided key. Returns the IV prepended to the ciphertext. +Future _encryptData(Uint8List data, SecretKey key) async { + try { + final gcm = AesGcm.with256bits(); + final iv = Uint8List(GCM_IV_SIZE) + ..setAll(0, List.generate(GCM_IV_SIZE, (i) => (i + 1) % 256)); + final secretBox = await gcm.encrypt(data, secretKey: key, nonce: iv); + return Uint8List.fromList(iv + secretBox.cipherText); + } catch (e) { + throw EncryptionException("Encryption failed", e); + } +} + +/// Encrypts the private key using the user's passkey/PIN. +/// Retrieves or generates the salt and stores it. +Future encryptPrivateKey( + Uint8List privateKey, String passkey, Uint8List salt) async { + if (salt.isEmpty) { + throw EncryptionException('Salt is empty'); + } + final key = await _deriveKeyFromPasskey(passkey, salt); + return await _encryptData(privateKey, key); +} diff --git a/data/pubspec.yaml b/data/pubspec.yaml index 6a1f7827..0034a4fe 100644 --- a/data/pubspec.yaml +++ b/data/pubspec.yaml @@ -33,6 +33,8 @@ dependencies: google_maps_flutter: ^2.2.8 connectivity_plus: ^6.0.5 battery_plus: ^6.2.0 + libsignal_protocol_dart: ^0.7.1 + cryptography_flutter: ^2.3.2 dev_dependencies: flutter_test: