-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
233b804
commit 2b5aacb
Showing
19 changed files
with
431 additions
and
113 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import 'package:dio/dio.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:shared_preferences/shared_preferences.dart'; | ||
import 'package:uneconly/common/database/database.dart'; | ||
import 'package:uneconly/feature/initialization/widget/inherited_dependencies.dart'; | ||
import 'package:uneconly/feature/settings/data/settings_repository.dart'; | ||
|
||
class Dependencies { | ||
Dependencies(); | ||
|
||
late final SharedPreferences sharedPreferences; | ||
late final ISettingsRepository settingsRepository; | ||
late final MyDatabase database; | ||
late final Dio dio; | ||
|
||
factory Dependencies.of(BuildContext context) => | ||
InheritedDependencies.of(context); | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// ignore_for_file: avoid_classes_with_only_static_members | ||
|
||
import 'dart:async'; | ||
|
||
import 'package:uneconly/common/util/platform/error_util_vm.dart' | ||
if (dart.library.html) 'package:uneconly/common/util/platform/error_util_js.dart'; | ||
import 'package:l/l.dart'; | ||
|
||
/// Error util. | ||
abstract final class ErrorUtil { | ||
/// Log the error to the console and to Crashlytics. | ||
static Future<void> logError( | ||
Object exception, | ||
StackTrace stackTrace, { | ||
String? hint, | ||
bool fatal = false, | ||
}) async { | ||
try { | ||
if (exception is String) { | ||
return await logMessage( | ||
exception, | ||
stackTrace: stackTrace, | ||
hint: hint, | ||
warning: true, | ||
); | ||
} | ||
$captureException(exception, stackTrace, hint, fatal).ignore(); | ||
l.e(exception, stackTrace); | ||
} on Object catch (error, stackTrace) { | ||
l.e( | ||
'Error while logging error "$error" inside ErrorUtil.logError', | ||
stackTrace, | ||
); | ||
} | ||
} | ||
|
||
/// Logs a message to the console and to Crashlytics. | ||
static Future<void> logMessage( | ||
String message, { | ||
StackTrace? stackTrace, | ||
String? hint, | ||
bool warning = false, | ||
}) async { | ||
try { | ||
l.e(message, stackTrace ?? StackTrace.current); | ||
$captureMessage(message, stackTrace, hint, warning).ignore(); | ||
} on Object catch (error, stackTrace) { | ||
l.e( | ||
'Error while logging error "$error" inside ErrorUtil.logMessage', | ||
stackTrace, | ||
); | ||
} | ||
} | ||
|
||
/// Rethrows the error with the stack trace. | ||
static Never throwWithStackTrace(Object error, StackTrace stackTrace) => | ||
Error.throwWithStackTrace(error, stackTrace); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
Future<void> $captureException( | ||
Object exception, | ||
StackTrace stackTrace, | ||
String? hint, | ||
bool fatal, | ||
) => | ||
Future<void>.value(null); | ||
|
||
Future<void> $captureMessage( | ||
String message, | ||
StackTrace? stackTrace, | ||
String? hint, | ||
bool warning, | ||
) => | ||
Future<void>.value(null); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
Future<void> $captureException( | ||
Object exception, | ||
StackTrace stackTrace, | ||
String? hint, | ||
bool fatal, | ||
) => | ||
Future<void>.value(); | ||
|
||
Future<void> $captureMessage( | ||
String message, | ||
StackTrace? stackTrace, | ||
String? hint, | ||
bool warning, | ||
) => | ||
Future<void>.value(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import 'package:flutter/material.dart'; | ||
|
||
/// {@template app_error} | ||
/// AppError widget | ||
/// {@endtemplate} | ||
class AppError extends StatelessWidget { | ||
/// {@macro app_error} | ||
const AppError({ | ||
this.error, | ||
Key? key, | ||
}) : super(key: key); | ||
|
||
/// Error | ||
final Object? error; | ||
|
||
@override | ||
Widget build(BuildContext context) => MaterialApp( | ||
title: 'App Error', | ||
theme: View.of(context).platformDispatcher.platformBrightness == | ||
Brightness.dark | ||
? ThemeData.dark(useMaterial3: true) | ||
: ThemeData.light(useMaterial3: true), | ||
home: Scaffold( | ||
body: SafeArea( | ||
child: Center( | ||
child: Padding( | ||
padding: const EdgeInsets.all(8), | ||
child: Text( | ||
// ErrorUtil.formatMessage(error) | ||
error?.toString() ?? 'Something went wrong', | ||
textScaler: TextScaler.noScaling, | ||
), | ||
), | ||
), | ||
), | ||
), | ||
builder: (context, child) => MediaQuery( | ||
data: MediaQuery.of(context).copyWith( | ||
textScaler: TextScaler.noScaling, | ||
), | ||
child: child!, | ||
), | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import 'dart:async'; | ||
import 'dart:ui'; | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:uneconly/common/model/dependencies.dart'; | ||
import 'package:uneconly/common/util/error_util.dart'; | ||
import 'package:uneconly/feature/initialization/data/initialize_dependencies.dart'; | ||
|
||
/// Ephemerally initializes the app and prepares it for use. | ||
Future<Dependencies>? _$initializeApp; | ||
|
||
/// Initializes the app and prepares it for use. | ||
Future<Dependencies> $initializeApp({ | ||
void Function(int progress, String message)? onProgress, | ||
FutureOr<void> Function(Dependencies dependencies)? onSuccess, | ||
void Function(Object error, StackTrace stackTrace)? onError, | ||
}) => | ||
_$initializeApp ??= Future<Dependencies>(() async { | ||
late final WidgetsBinding binding; | ||
final stopwatch = Stopwatch()..start(); | ||
try { | ||
binding = WidgetsFlutterBinding.ensureInitialized()..deferFirstFrame(); | ||
await _catchExceptions(); | ||
final dependencies = | ||
await $initializeDependencies(onProgress: onProgress) | ||
.timeout(const Duration(minutes: 7)); | ||
await onSuccess?.call(dependencies); | ||
|
||
return dependencies; | ||
} on Object catch (error, stackTrace) { | ||
onError?.call(error, stackTrace); | ||
ErrorUtil.logError(error, stackTrace, hint: 'Failed to initialize app') | ||
.ignore(); | ||
rethrow; | ||
} finally { | ||
stopwatch.stop(); | ||
binding.addPostFrameCallback((_) { | ||
// Closes splash screen, and show the app layout. | ||
binding.allowFirstFrame(); | ||
//final context = binding.renderViewElement; | ||
}); | ||
_$initializeApp = null; | ||
} | ||
}); | ||
|
||
/// Resets the app's state to its initial state. | ||
@visibleForTesting | ||
Future<void> $resetApp(Dependencies dependencies) async {} | ||
|
||
/// Disposes the app and releases all resources. | ||
@visibleForTesting | ||
Future<void> $disposeApp(Dependencies dependencies) async {} | ||
|
||
Future<void> _catchExceptions() async { | ||
try { | ||
PlatformDispatcher.instance.onError = (error, stackTrace) { | ||
ErrorUtil.logError( | ||
error, | ||
stackTrace, | ||
hint: 'ROOT ERROR\r\n${Error.safeToString(error)}', | ||
).ignore(); | ||
|
||
return true; | ||
}; | ||
|
||
final sourceFlutterError = FlutterError.onError; | ||
FlutterError.onError = (final details) { | ||
ErrorUtil.logError( | ||
details.exception, | ||
details.stack ?? StackTrace.current, | ||
hint: 'FLUTTER ERROR\r\n$details', | ||
).ignore(); | ||
// FlutterError.presentError(details); | ||
sourceFlutterError?.call(details); | ||
}; | ||
} on Object catch (error, stackTrace) { | ||
ErrorUtil.logError(error, stackTrace).ignore(); | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
lib/feature/initialization/data/initialize_dependencies.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:dio/dio.dart'; | ||
import 'package:l/l.dart'; | ||
import 'package:shared_preferences/shared_preferences.dart'; | ||
import 'package:uneconly/common/database/database.dart'; | ||
import 'package:uneconly/common/model/dependencies.dart'; | ||
import 'package:uneconly/constants.dart'; | ||
import 'package:uneconly/feature/initialization/data/platform/platform_initialization.dart'; | ||
import 'package:uneconly/feature/settings/data/settings_local_data_provider.dart'; | ||
import 'package:uneconly/feature/settings/data/settings_repository.dart'; | ||
|
||
/// Initializes the app and returns a [Dependencies] object | ||
Future<Dependencies> $initializeDependencies({ | ||
void Function(int progress, String message)? onProgress, | ||
}) async { | ||
final dependencies = Dependencies(); | ||
final totalSteps = _initializationSteps.length; | ||
var currentStep = 0; | ||
for (final step in _initializationSteps.entries) { | ||
try { | ||
currentStep++; | ||
final percent = (currentStep * 100 ~/ totalSteps).clamp(0, 100); | ||
onProgress?.call(percent, step.key); | ||
l.v6( | ||
'Initialization | $currentStep/$totalSteps ($percent%) | "${step.key}"', | ||
); | ||
await step.value(dependencies); | ||
} on Object catch (error, stackTrace) { | ||
l.e('Initialization failed at step "${step.key}": $error', stackTrace); | ||
Error.throwWithStackTrace( | ||
'Initialization failed at step "${step.key}": $error', | ||
stackTrace, | ||
); | ||
} | ||
} | ||
return dependencies; | ||
} | ||
|
||
typedef _InitializationStep = FutureOr<void> Function( | ||
Dependencies dependencies, | ||
); | ||
final Map<String, _InitializationStep> _initializationSteps = | ||
<String, _InitializationStep>{ | ||
'Platform pre-initialization': (_) => $platformInitialization(), | ||
'Log app open': (_) {}, | ||
'Initialize shared preferences': (dependencies) async => | ||
dependencies.sharedPreferences = await SharedPreferences.getInstance(), | ||
'Initialize settings repository': (dependencies) async => | ||
dependencies.settingsRepository = SettingsRepository( | ||
localDataProvider: SettingsLocalDataProvider( | ||
prefs: dependencies.sharedPreferences, | ||
), | ||
), | ||
'Initialize database': (dependencies) async => | ||
dependencies.database = MyDatabase(), | ||
'Initialize dio': (dependencies) async => dependencies.dio = Dio( | ||
BaseOptions( | ||
baseUrl: serverAddress, | ||
), | ||
), | ||
'Log app initialized': (_) {}, | ||
}; |
2 changes: 2 additions & 0 deletions
2
lib/feature/initialization/data/platform/platform_initialization.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export 'platform_initialization_vm.dart' | ||
if (dart.library.html) 'platform_initialization_js.dart'; |
10 changes: 10 additions & 0 deletions
10
lib/feature/initialization/data/platform/platform_initialization_js.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import 'dart:io' as io; | ||
|
||
Future<void> $platformInitialization() => | ||
io.Platform.isAndroid || io.Platform.isIOS | ||
? _mobileInitialization() | ||
: _desktopInitialization(); | ||
|
||
Future<void> _mobileInitialization() async {} | ||
|
||
Future<void> _desktopInitialization() async {} |
3 changes: 3 additions & 0 deletions
3
lib/feature/initialization/data/platform/platform_initialization_vm.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Future<void> $platformInitialization() async { | ||
//setUrlStrategy(const HashUrlStrategy()); | ||
} |
29 changes: 29 additions & 0 deletions
29
lib/feature/initialization/widget/inherited_dependencies.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:uneconly/common/model/dependencies.dart'; | ||
|
||
class InheritedDependencies extends InheritedWidget { | ||
final Dependencies dependencies; | ||
|
||
const InheritedDependencies({ | ||
required this.dependencies, | ||
required super.child, | ||
super.key, | ||
}); | ||
|
||
static Dependencies of(BuildContext context) => | ||
maybeOf(context) ?? _notFoundInheritedWidgetOfExactType(); | ||
|
||
static Dependencies? maybeOf(BuildContext context) => (context | ||
.getElementForInheritedWidgetOfExactType<InheritedDependencies>() | ||
?.widget as InheritedDependencies?) | ||
?.dependencies; | ||
|
||
static Never _notFoundInheritedWidgetOfExactType() => throw ArgumentError( | ||
'Out of scope, not found inherited widget ' | ||
'a InheritedDependencies of the exact type', | ||
'out_of_scope', | ||
); | ||
|
||
@override | ||
bool updateShouldNotify(InheritedDependencies oldWidget) => false; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.