better app initialization with bangs

This commit is contained in:
Fabian Freund
2024-06-12 08:37:58 +02:00
parent b1e2b65a0c
commit 9bd30208b3
5 changed files with 133 additions and 44 deletions
@@ -0,0 +1,54 @@
import 'package:bang_navigator/features/about/data/repositories/package_info_repository.dart';
import 'package:bang_navigator/features/bangs/domain/repositories/sync.dart';
import 'package:bang_navigator/features/search_browser/domain/services/session.dart';
import 'package:bang_navigator/features/settings/data/repositories/settings_repository.dart';
import 'package:exceptions/exceptions.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'app_initialization.g.dart';
@Riverpod(keepAlive: true)
class AppInitializationService extends _$AppInitializationService {
/// Will de facto restart the app
Future<void> reinitialize() async {
ref.invalidateSelf();
return initialize();
}
Future<void> initialize() async {
state = await Result.fromAsync(() async {
final errors = <ErrorMessage>[];
//Ensure Package info is loaded
await ref.read(packageInfoProvider.future);
final syncResults = await ref
.read(bangSyncRepositoryProvider.notifier)
.syncAllBangGroups(syncInterval: const Duration(days: 7));
for (final MapEntry(value: result) in syncResults.entries) {
result.onFailure(errors.add);
}
final settings = await ref.read(settingsRepositoryProvider.future);
if (settings.incognitoMode) {
await ref.read(sessionServiceProvider.notifier).clearAllData();
}
if (settings.kagiSession case final String session) {
if (session.isNotEmpty) {
await ref
.read(sessionServiceProvider.notifier)
.setKagiSession(session);
}
}
return (initialized: true, errors: errors);
});
}
@override
Result<({bool initialized, List<ErrorMessage> errors})> build() {
return Result.success((initialized: false, errors: List.empty()));
}
}
@@ -0,0 +1,29 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'app_initialization.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$appInitializationServiceHash() =>
r'7b36828c2368c3b3a97b799dd8192854629c8379';
/// See also [AppInitializationService].
@ProviderFor(AppInitializationService)
final appInitializationServiceProvider = NotifierProvider<
AppInitializationService,
Result<({bool initialized, List<ErrorMessage> errors})>>.internal(
AppInitializationService.new,
name: r'appInitializationServiceProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$appInitializationServiceHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$AppInitializationService
= Notifier<Result<({bool initialized, List<ErrorMessage> errors})>>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
@@ -44,10 +44,6 @@ class SessionService extends _$SessionService {
await webViewLoaded.future.whenComplete(() => headlessWebView..dispose()); await webViewLoaded.future.whenComplete(() => headlessWebView..dispose());
} }
void initializationDone() {
state = true;
}
@override @override
bool build() => false; void build() {}
} }
@@ -6,12 +6,12 @@ part of 'session.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$sessionServiceHash() => r'48126bad2cb8d5c38296307bede64bf549365acf'; String _$sessionServiceHash() => r'fd2cd03bbf2dd254bb19e541c71a6fb249f5a7bb';
/// See also [SessionService]. /// See also [SessionService].
@ProviderFor(SessionService) @ProviderFor(SessionService)
final sessionServiceProvider = final sessionServiceProvider =
AutoDisposeNotifierProvider<SessionService, bool>.internal( AutoDisposeNotifierProvider<SessionService, void>.internal(
SessionService.new, SessionService.new,
name: r'sessionServiceProvider', name: r'sessionServiceProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
@@ -21,6 +21,6 @@ final sessionServiceProvider =
allTransitiveDependencies: null, allTransitiveDependencies: null,
); );
typedef _$SessionService = AutoDisposeNotifier<bool>; typedef _$SessionService = AutoDisposeNotifier<void>;
// ignore_for_file: type=lint // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
+46 -36
View File
@@ -1,11 +1,10 @@
import 'package:bang_navigator/core/logger.dart'; import 'package:bang_navigator/core/logger.dart';
import 'package:bang_navigator/core/providers.dart'; import 'package:bang_navigator/core/providers.dart';
import 'package:bang_navigator/features/about/data/repositories/package_info_repository.dart'; import 'package:bang_navigator/domain/services/app_initialization.dart';
import 'package:bang_navigator/features/bangs/domain/repositories/sync.dart';
import 'package:bang_navigator/features/search_browser/domain/services/session.dart';
import 'package:bang_navigator/features/settings/data/repositories/settings_repository.dart';
import 'package:bang_navigator/presentation/hooks/on_initialization.dart'; import 'package:bang_navigator/presentation/hooks/on_initialization.dart';
import 'package:bang_navigator/presentation/widgets/failure_widget.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:home_widget/home_widget.dart'; import 'package:home_widget/home_widget.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -39,28 +38,9 @@ void main() async {
builder: (context, ref, child) { builder: (context, ref, child) {
useOnInitialization( useOnInitialization(
() async { () async {
await ref.read(packageInfoProvider.future);
await ref await ref
.read(bangSyncRepositoryProvider.notifier) .read(appInitializationServiceProvider.notifier)
.syncAllBangGroups(syncInterval: const Duration(days: 7)); .initialize();
final settings =
await ref.read(settingsRepositoryProvider.future);
if (settings.incognitoMode) {
await ref.read(sessionServiceProvider.notifier).clearAllData();
}
if (settings.kagiSession case final String session) {
if (session.isNotEmpty) {
await ref
.read(sessionServiceProvider.notifier)
.setKagiSession(session);
}
}
ref.read(sessionServiceProvider.notifier).initializationDone();
}, },
); );
@@ -76,18 +56,11 @@ class MainApp extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final isInitialized = ref.watch(sessionServiceProvider); final initializationResult = ref.watch(appInitializationServiceProvider);
final router = ref.watch(routerProvider); final router = ref.watch(routerProvider);
if (!isInitialized) { final themeData = useMemoized(
return const Center( () => ThemeData(
child: CircularProgressIndicator(),
);
}
return MaterialApp.router(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true, useMaterial3: true,
brightness: Brightness.dark, brightness: Brightness.dark,
// colorScheme: ColorScheme.fromSeed( // colorScheme: ColorScheme.fromSeed(
@@ -95,7 +68,44 @@ class MainApp extends HookConsumerWidget {
// brightness: Brightness.dark, // brightness: Brightness.dark,
// ), // ),
), ),
routerConfig: router, );
return initializationResult.fold(
(initializationState) {
if (!initializationState.initialized) {
return const Center(
child: CircularProgressIndicator(),
);
}
return MaterialApp.router(
debugShowCheckedModeBanner: false,
theme: themeData,
routerConfig: router,
);
},
onFailure: (errorMessage) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: themeData,
home: Scaffold(
appBar: AppBar(
title: const Text('Initiallization Error'),
),
body: Center(
child: FailureWidget(
title: 'Could not initialize App',
exception: errorMessage.toString(),
onRetry: () async {
await ref
.read(appInitializationServiceProvider.notifier)
.reinitialize();
},
),
),
),
);
},
); );
} }
} }