diff --git a/lib/main.data.dart b/lib/main.data.dart index de65e8e..109938b 100644 --- a/lib/main.data.dart +++ b/lib/main.data.dart @@ -9,12 +9,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:zapstore/models/app.dart'; import 'package:zapstore/models/file_metadata.dart'; import 'package:zapstore/models/release.dart'; +import 'package:zapstore/models/settings.dart'; import 'package:zapstore/models/user.dart'; final adapterProvidersMap = >>{ 'apps': appsAdapterProvider, 'fileMetadata': fileMetadataAdapterProvider, 'releases': releasesAdapterProvider, +'settings': settingsAdapterProvider, 'users': usersAdapterProvider }; @@ -22,6 +24,7 @@ extension AdapterWidgetRefX on WidgetRef { Adapter get apps => watch(appsAdapterProvider)..internalWatch = watch; Adapter get fileMetadata => watch(fileMetadataAdapterProvider)..internalWatch = watch; Adapter get releases => watch(releasesAdapterProvider)..internalWatch = watch; + Adapter get settings => watch(settingsAdapterProvider)..internalWatch = watch; Adapter get users => watch(usersAdapterProvider)..internalWatch = watch; } @@ -30,5 +33,6 @@ extension AdapterRefX on Ref { Adapter get apps => watch(appsAdapterProvider)..internalWatch = watch as Watcher; Adapter get fileMetadata => watch(fileMetadataAdapterProvider)..internalWatch = watch as Watcher; Adapter get releases => watch(releasesAdapterProvider)..internalWatch = watch as Watcher; + Adapter get settings => watch(settingsAdapterProvider)..internalWatch = watch as Watcher; Adapter get users => watch(usersAdapterProvider)..internalWatch = watch as Watcher; } \ No newline at end of file diff --git a/lib/models/settings.dart b/lib/models/settings.dart new file mode 100644 index 0000000..b06b61a --- /dev/null +++ b/lib/models/settings.dart @@ -0,0 +1,25 @@ +import 'package:flutter_data/flutter_data.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:zapstore/models/user.dart'; + +part 'settings.g.dart'; + +@JsonSerializable() +@DataAdapter([SettingsAdapter]) +class Settings extends DataModel { + @override + String get id => '_'; + final BelongsTo user = BelongsTo(); + bool isLoggedIn = false; +} + +mixin SettingsAdapter on Adapter { + @override + Future onInitialized() async { + // ensure it's always present + if (!existsId('_')) { + Settings().saveLocal(); + } + super.onInitialized(); + } +} diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart new file mode 100644 index 0000000..621225e --- /dev/null +++ b/lib/models/settings.g.dart @@ -0,0 +1,68 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'settings.dart'; + +// ************************************************************************** +// AdapterGenerator +// ************************************************************************** + +// ignore_for_file: non_constant_identifier_names, duplicate_ignore + +mixin _$SettingsAdapter on Adapter { + static final Map _kSettingsRelationshipMetas = { + 'user': RelationshipMeta( + name: 'user', + type: 'users', + kind: 'BelongsTo', + instance: (_) => (_ as Settings).user, + ) + }; + + @override + Map get relationshipMetas => + _kSettingsRelationshipMetas; + + @override + Settings deserializeLocal(map, {String? key}) { + map = transformDeserialize(map); + return internalWrapStopInit(() => _$SettingsFromJson(map), key: key); + } + + @override + Map serializeLocal(model, {bool withRelationships = true}) { + final map = _$SettingsToJson(model); + return transformSerialize(map, withRelationships: withRelationships); + } +} + +final _settingsFinders = {}; + +class $SettingsAdapter = Adapter + with _$SettingsAdapter, SettingsAdapter; + +final settingsAdapterProvider = Provider>( + (ref) => $SettingsAdapter(ref, InternalHolder(_settingsFinders))); + +extension SettingsAdapterX on Adapter { + SettingsAdapter get settingsAdapter => this as SettingsAdapter; +} + +extension SettingsRelationshipGraphNodeX on RelationshipGraphNode { + RelationshipGraphNode get user { + final meta = _$SettingsAdapter._kSettingsRelationshipMetas['user'] + as RelationshipMeta; + return meta.clone( + parent: this is RelationshipMeta ? this as RelationshipMeta : null); + } +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Settings _$SettingsFromJson(Map json) => + Settings()..isLoggedIn = json['isLoggedIn'] as bool; + +Map _$SettingsToJson(Settings instance) => { + 'isLoggedIn': instance.isLoggedIn, + }; diff --git a/lib/screens/app_detail_screen.dart b/lib/screens/app_detail_screen.dart index e412202..2d17013 100644 --- a/lib/screens/app_detail_screen.dart +++ b/lib/screens/app_detail_screen.dart @@ -14,7 +14,6 @@ import 'package:zapstore/main.data.dart'; import 'package:zapstore/models/app.dart'; import 'package:zapstore/models/release.dart'; import 'package:zapstore/models/user.dart'; -import 'package:zapstore/services/session_service.dart'; import 'package:zapstore/utils/extensions.dart'; import 'package:zapstore/widgets/card.dart'; import 'package:zapstore/widgets/pill_widget.dart'; @@ -116,7 +115,7 @@ class AppDetailScreen extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SizedBox(child: Text('Source')), + SizedBox(child: Text('Source ')), Flexible( child: AutoSizeText( app.repository!, @@ -172,7 +171,7 @@ class AppDetailScreen extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('SHA-256 hash'), + Text('SHA-256 hash '), Flexible( child: Text( '${app.latestMetadata!.hash!.substring(0, 26)}...', @@ -454,8 +453,8 @@ class InstallButton extends ConsumerWidget { child: switch (app.status) { AppInstallStatus.noArch => Text('Sorry, release does not support your device'), - AppInstallStatus.downgrade => - Text('Installed version is higher, can\'t downgrade'), + AppInstallStatus.downgrade => Text( + 'Installed version ${app.installedVersion ?? ''} is higher, can\'t downgrade'), AppInstallStatus.updated => Text('Open'), _ => switch (progress) { IdleInstallProgress() => app.canUpdate @@ -492,7 +491,7 @@ class InstallAlertDialog extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final user = ref.watch(loggedInUser); + final user = ref.settings.watchOne('_').model!.user.value; return AlertDialog( elevation: 10, title: Text( diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 5edf21d..e8f3af1 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -7,7 +7,6 @@ import 'package:purplebase/purplebase.dart'; import 'package:zapstore/main.dart'; import 'package:zapstore/main.data.dart'; import 'package:zapstore/models/app.dart'; -import 'package:zapstore/services/session_service.dart'; import 'package:zapstore/utils/extensions.dart'; class SettingsScreen extends HookConsumerWidget { @@ -16,6 +15,8 @@ class SettingsScreen extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final controller = useTextEditingController(); + final user = ref.settings.watchOne('_').model!.user.value; + return SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.start, @@ -44,7 +45,6 @@ class SettingsScreen extends HookConsumerWidget { loadingWidget: SizedBox( width: 14, height: 14, child: CircularProgressIndicator()), onPressed: () async { - final user = ref.read(loggedInUser); if (user == null) { scaffoldKey.currentState!.openDrawer(); return; @@ -61,8 +61,7 @@ class SettingsScreen extends HookConsumerWidget { child: child, ); }, - child: Text( - ref.watch(loggedInUser) != null ? 'Send' : 'Tap to log in'), + child: Text(user != null ? 'Send' : 'Tap to log in'), ), ], ), diff --git a/lib/services/session_service.dart b/lib/services/session_service.dart deleted file mode 100644 index 49f2342..0000000 --- a/lib/services/session_service.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:zapstore/models/user.dart'; - -final loggedInUser = StateProvider((ref) => null); diff --git a/lib/widgets/app_drawer.dart b/lib/widgets/app_drawer.dart index 273ae30..9adc9ab 100644 --- a/lib/widgets/app_drawer.dart +++ b/lib/widgets/app_drawer.dart @@ -4,7 +4,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:zapstore/main.data.dart'; -import 'package:zapstore/services/session_service.dart'; +import 'package:zapstore/models/settings.dart'; import 'package:zapstore/widgets/card.dart'; class AppDrawer extends HookConsumerWidget { @@ -12,7 +12,11 @@ class AppDrawer extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final user = ref.watch(loggedInUser); + final user = ref.settings + .watchOne('_', alsoWatch: (_) => {_.user}) + .model + ?.user + .value; final controller = useTextEditingController(); return Padding( @@ -44,8 +48,8 @@ class AppDrawer extends HookConsumerWidget { color: Colors.lightBlue, size: 18), ], ), - if (user.following.isNotEmpty) - Text('${user.following.length} contacts'), + // if (user.following.isNotEmpty) + // Text('${user.following.length} contacts'), ], ), ], @@ -69,9 +73,9 @@ class AppDrawer extends HookConsumerWidget { child: CircularProgressIndicator(), ), onPressed: () async { - ref.read(loggedInUser.notifier).state = await ref.users - .findOne(controller.text.trim(), - params: {'contacts': true}); + final user = + await ref.users.findOne(controller.text.trim()); + ref.settings.findOneLocalById('_')!.user.value = user; }, builder: (context, child, callback, buttonState) { return ElevatedButton( @@ -84,7 +88,7 @@ class AppDrawer extends HookConsumerWidget { if (user != null) ElevatedButton( onPressed: () async { - ref.read(loggedInUser.notifier).state = null; + ref.settings.findOneLocalById('_')!.user.value = null; controller.clear(); }, child: Text('Log out'), diff --git a/lib/widgets/user_avatar.dart b/lib/widgets/user_avatar.dart index 39d2c95..1193af3 100644 --- a/lib/widgets/user_avatar.dart +++ b/lib/widgets/user_avatar.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:zapstore/services/session_service.dart'; +import 'package:zapstore/main.data.dart'; import 'package:zapstore/widgets/card.dart'; class UserAvatar extends HookConsumerWidget { @@ -8,7 +8,7 @@ class UserAvatar extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final user = ref.watch(loggedInUser); + final user = ref.settings.watchOne('_').model!.user.value; return CircularImage(url: user?.avatarUrl, size: 46); } }