feat(app): Вынести инициализацию приложения за splash (#4)

Co-authored-by: PetrovY <y.petrov@friflex.com>
This commit is contained in:
Yuri Petrov
2025-02-12 10:53:38 +03:00
committed by GitHub
parent 0a7452e1eb
commit af3b941711
18 changed files with 503 additions and 155 deletions

View File

@@ -1,46 +1,96 @@
import 'package:flutter/material.dart';
import 'package:friflex_starter/app/app_context_ext.dart';
import 'package:friflex_starter/app/app_providers.dart';
import 'package:friflex_starter/app/depends_providers.dart';
import 'package:friflex_starter/app/theme/app_theme.dart';
import 'package:friflex_starter/app/theme/theme_notifier.dart';
import 'package:friflex_starter/di/di_container.dart';
import 'package:friflex_starter/features/error/error_screen.dart';
import 'package:friflex_starter/features/splash/splash_screen.dart';
import 'package:friflex_starter/l10n/gen/app_localizations.dart';
import 'package:friflex_starter/l10n/localization_notifier.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
/// Класс для реализации объекта приложения
class App extends StatelessWidget {
/// Создает экземпляр приложения
///
/// Принимает:
/// - [diContainer] - набор зависимостей приложения
/// - [router] - экземпляр роутера приложения
/// Класс приложения
class App extends StatefulWidget {
const App({
super.key,
required this.diContainer,
required this.router,
required this.initDependencies,
});
/// Набор зависимостей приложения
final DiContainer diContainer;
/// Экземпляр роутера приложения
/// Роутер приложения
final GoRouter router;
/// Функция для инициализации зависимостей
final Future<DiContainer> Function() initDependencies;
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
/// Мутабельная Future для инициализации зависимостей
late Future<DiContainer> _initFuture;
@override
void initState() {
super.initState();
_initFuture = widget.initDependencies();
}
@override
Widget build(BuildContext context) {
return AppProviders(
diContainer: diContainer,
// Consumer для локализации добавляем выше чем DependsProviders
// чтобы при изменении локализации перестраивался весь виджет
// Но, это не обязательно, можно добавить в DependsProviders
child: LocalizationConsumer(
builder: () => ThemeConsumer(
builder: () => _App(router: router),
builder: () => FutureBuilder<DiContainer>(
future: _initFuture,
builder: (_, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
case ConnectionState.active:
// Пока инициализация показываем Splash
return const SplashScreen();
case ConnectionState.done:
if (snapshot.hasError) {
return ErrorScreen(
error: snapshot.error,
stackTrace: snapshot.stackTrace,
onRetry: _retryInit,
);
}
final diContainer = snapshot.data;
if (diContainer == null) {
return ErrorScreen(
error:
'Ошибка инициализации зависимостей, diContainer = null',
stackTrace: null,
onRetry: _retryInit,
);
}
return DependsProviders(
diContainer: diContainer,
child: ThemeConsumer(
builder: () => _App(router: widget.router),
),
);
}
},
),
),
);
}
void _retryInit() {
setState(() {
_initFuture = widget.initDependencies();
});
}
}
/// Класс для реализации объекта приложения
class _App extends StatelessWidget {
const _App({required this.router});
@@ -59,31 +109,3 @@ class _App extends StatelessWidget {
);
}
}
/// Класс для реализации провайдеров приложения
final class AppProviders extends StatelessWidget {
const AppProviders({
super.key,
required this.child,
required this.diContainer,
});
final Widget child;
final DiContainer diContainer;
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
Provider.value(value: diContainer), // Передаем контейнер зависимостей
ChangeNotifierProvider(
create: (_) => ThemeNotifier(),
), // Провайдер для темы
ChangeNotifierProvider(
create: (_) => LocalizationNotifier(),
), // Провайдер для локализации
],
child: child,
);
}
}

View File

@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:friflex_starter/app/theme/theme_notifier.dart';
import 'package:friflex_starter/l10n/localization_notifier.dart';
import 'package:provider/provider.dart';
/// Класс для добавления провайдеров темы и локализации
final class AppProviders extends StatelessWidget {
const AppProviders({
super.key,
required this.child,
});
final Widget child;
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => ThemeNotifier(),
), // Провайдер для темы
ChangeNotifierProvider(
create: (_) => LocalizationNotifier(),
), // Провайдер для локализации
],
child: child,
);
}
}

View File

@@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
import 'package:friflex_starter/di/di_container.dart';
import 'package:provider/provider.dart';
/// Класс для внедрения глобальных зависимостей
final class DependsProviders extends StatelessWidget {
const DependsProviders({
super.key,
required this.child,
required this.diContainer,
});
final Widget child;
final DiContainer diContainer;
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
// Сюда добавляем глобальные блоки, inherited и т.д.
Provider.value(value: diContainer), // Передаем контейнер зависимостей
],
child: child,
);
}
}