Fix for loop
This commit is contained in:
@@ -15,8 +15,13 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
on<AuthLoggedOut>(_onAuthLoggedOut);
|
||||
}
|
||||
|
||||
void _onAuthStarted(AuthStarted event, Emitter<AuthState> emit) {
|
||||
// Получаем текущее состояние пользователя из UserCubit
|
||||
void _onAuthStarted(AuthStarted event, Emitter<AuthState> emit) async {
|
||||
// Комментарий: Инициализируем UserCubit при старте AuthBloc.
|
||||
// Это гарантирует, что UserCubit загрузит данные пользователя
|
||||
// перед тем, как AuthBloc будет принимать решение об аутентификации.
|
||||
await _userCubit.init();
|
||||
|
||||
// Получаем текущее состояние пользователя из UserCubit после инициализации
|
||||
final userState = _userCubit.state;
|
||||
if (userState is UserLoaded && userState.user != null) {
|
||||
emit(AuthAuthenticated(user: userState.user!));
|
||||
@@ -26,6 +31,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
}
|
||||
|
||||
void _onAuthLoggedIn(AuthLoggedIn event, Emitter<AuthState> emit) {
|
||||
// Комментарий: Обновляем UserCubit с новым пользователем.
|
||||
_userCubit.setUser(event.user);
|
||||
emit(AuthAuthenticated(user: event.user));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
import '/data/repositories/interfaces/iglobal_settings_repository.dart';
|
||||
import '/data/repositories/interfaces/iuser_repository.dart';
|
||||
import '/data/repositories/interfaces/icategory_repository.dart';
|
||||
import '/data/repositories/interfaces/iglobal_settings_repository.dart';
|
||||
import '/data/repositories/interfaces/itag_repository.dart';
|
||||
import '/data/repositories/interfaces/itransaction_repository.dart';
|
||||
import '/data/repositories/interfaces/iuser_repository.dart';
|
||||
import '/models/user.dart';
|
||||
import '/utils/category_utils.dart';
|
||||
import '/utils/tag_utils.dart';
|
||||
import '/utils/transaction_utils.dart';
|
||||
|
||||
part 'user_state.dart';
|
||||
|
||||
/// Cubit для управления состоянием пользователя
|
||||
@@ -29,21 +31,26 @@ class UserCubit extends Cubit<UserState> {
|
||||
required ICategoryRepository categoryRepository,
|
||||
required ITagRepository tagRepository,
|
||||
required ITransactionRepository transactionRepository,
|
||||
}) : _settingsRepository = settingsRepository,
|
||||
_userRepository = userRepository,
|
||||
_categoryRepository = categoryRepository,
|
||||
_tagRepository = tagRepository,
|
||||
_transactionRepository = transactionRepository,
|
||||
super(UserInitial()) {
|
||||
_init();
|
||||
}) : _settingsRepository = settingsRepository,
|
||||
_userRepository = userRepository,
|
||||
_categoryRepository = categoryRepository,
|
||||
_tagRepository = tagRepository,
|
||||
_transactionRepository = transactionRepository,
|
||||
super(UserInitial());
|
||||
|
||||
// Метод для инициализации UserCubit
|
||||
Future<void> init() async {
|
||||
await _init();
|
||||
}
|
||||
|
||||
Future<void> _init() async {
|
||||
emit(UserLoading());
|
||||
emit(UserLoading(progress: 0.1, message: 'Поиск пользователя...'));
|
||||
try {
|
||||
// Этап 1: Проверка существующего пользователя
|
||||
final userId = await _settingsRepository.getCurrentUserId();
|
||||
emit(UserLoading(progress: 0.3, message: 'Проверка пользователя...'));
|
||||
|
||||
User? currentUser;
|
||||
|
||||
if (userId != null) {
|
||||
currentUser = await _userRepository.getById(userId);
|
||||
if (currentUser == null) {
|
||||
@@ -52,18 +59,30 @@ class UserCubit extends Cubit<UserState> {
|
||||
}
|
||||
}
|
||||
|
||||
// Этап 2: Создание пользователя по умолчанию при необходимости
|
||||
if (currentUser == null) {
|
||||
emit(UserLoading(progress: 0.5, message: 'Проверка данных...'));
|
||||
final allUsers = await _userRepository.getAll();
|
||||
if (allUsers.isEmpty) {
|
||||
_logger.i('No users found, creating default user');
|
||||
currentUser = await _createDefaultUser();
|
||||
emit(UserLoading(progress: 0.6, message: 'Создание пользователя...'));
|
||||
// Комментарий: Вызываем создание пользователя по умолчанию.
|
||||
// Этот метод сам установит состояние UserLoaded, поэтому после него нужно завершить выполнение _init.
|
||||
await _createDefaultUser();
|
||||
return;
|
||||
} else {
|
||||
_logger.i('Setting first user as current');
|
||||
currentUser = allUsers.first;
|
||||
// Комментарий: Устанавливаем первого пользователя как текущего.
|
||||
// Этот метод также устанавливает состояние UserLoaded, поэтому выходим.
|
||||
await _setCurrentUser(currentUser);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Этап 3: Завершение инициализации (этот блок теперь выполняется только для уже существующих пользователей)
|
||||
emit(UserLoading(progress: 1.0, message: 'Завершение...'));
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
emit(UserLoaded(currentUser));
|
||||
} catch (e, stack) {
|
||||
_logger.e('Error initializing user cubit', error: e, stackTrace: stack);
|
||||
@@ -85,28 +104,29 @@ class UserCubit extends Cubit<UserState> {
|
||||
return user;
|
||||
}
|
||||
|
||||
/// Создает начальные данные для нового пользователя (категории, теги, транзакции)
|
||||
Future<void> _createInitialData(String userId) async {
|
||||
try {
|
||||
// Добавляем начальные категории
|
||||
// Разбиваем создание данных на этапы
|
||||
emit(UserLoading(progress: 0.7, message: 'Создание категорий...'));
|
||||
await _categoryRepository.addAll(
|
||||
CategoryUtils.getDefaultCategories(userId),
|
||||
);
|
||||
|
||||
// Добавляем начальные теги
|
||||
await _tagRepository.addAll(
|
||||
TagUtils.getDefaultTags(userId),
|
||||
);
|
||||
emit(UserLoading(progress: 0.8, message: 'Создание тегов...'));
|
||||
await _tagRepository.addAll(TagUtils.getDefaultTags(userId));
|
||||
|
||||
// Добавляем примеры транзакций
|
||||
emit(UserLoading(progress: 0.9, message: 'Создание транзакций...'));
|
||||
await _transactionRepository.addAll(
|
||||
TransactionUtils.getSampleTransactions(userId),
|
||||
);
|
||||
|
||||
_logger.i('Initial data created for user: $userId');
|
||||
} catch (e, stack) {
|
||||
_logger.e('Error creating initial data for user: $userId', error: e, stackTrace: stack);
|
||||
// Не прерываем создание пользователя из-за ошибки создания начальных данных
|
||||
_logger.e(
|
||||
'Error creating initial data for user: $userId',
|
||||
error: e,
|
||||
stackTrace: stack,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +146,11 @@ class UserCubit extends Cubit<UserState> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Устанавливает текущего пользователя (прямая установка без загрузки)
|
||||
void setUser(User user) {
|
||||
emit(UserLoaded(user));
|
||||
}
|
||||
|
||||
/// Выход из системы
|
||||
Future<void> logout() async {
|
||||
emit(UserLoading());
|
||||
@@ -142,10 +167,7 @@ class UserCubit extends Cubit<UserState> {
|
||||
Future<void> createAndSetUser(String name, String email) async {
|
||||
emit(UserLoading());
|
||||
try {
|
||||
final user = User(
|
||||
name: name,
|
||||
email: email,
|
||||
);
|
||||
final user = User(name: name, email: email);
|
||||
await _userRepository.add(user);
|
||||
|
||||
// Создаем начальные данные для нового пользователя
|
||||
@@ -168,4 +190,3 @@ class UserCubit extends Cubit<UserState> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,15 @@ class UserInitial extends UserState {
|
||||
const UserInitial();
|
||||
}
|
||||
|
||||
/// Состояние загрузки данных
|
||||
/// Состояние загрузки данных с прогрессом и сообщением
|
||||
class UserLoading extends UserState {
|
||||
const UserLoading();
|
||||
final double progress;
|
||||
final String message;
|
||||
|
||||
const UserLoading({
|
||||
this.progress = 0.0,
|
||||
this.message = '',
|
||||
});
|
||||
}
|
||||
|
||||
/// Состояние успешной загрузки пользователя
|
||||
|
||||
+76
-46
@@ -1,17 +1,34 @@
|
||||
import 'package:budget_app/pages/home/home_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart'; // Добавляем импорт
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
import '/l10n/app_localizations.dart';
|
||||
import 'logic/auth/auth_bloc.dart';
|
||||
import 'pages/login/login_page.dart';
|
||||
import 'package:budget_app/pages/home/home_page.dart';
|
||||
import 'theme/app_theme.dart';
|
||||
import 'injection_container.dart' as di;
|
||||
import 'logic/auth/auth_bloc.dart';
|
||||
import 'logic/settings/settings_cubit.dart'; // Импортируем SettingsCubit
|
||||
import 'logic/sms/sms_cubit.dart';
|
||||
import 'logic/transaction/transaction_bloc.dart';
|
||||
import 'logic/user/user_cubit.dart'; // Импортируем UserCubit
|
||||
import 'pages/login/login_page.dart';
|
||||
import 'theme/app_theme.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
|
||||
import '/l10n/app_localizations.dart';
|
||||
import '/logic/auth/auth_bloc.dart';
|
||||
import '/logic/settings/settings_cubit.dart';
|
||||
import '/logic/sms/sms_cubit.dart';
|
||||
import '/logic/transaction/transaction_bloc.dart';
|
||||
import '/logic/user/user_cubit.dart';
|
||||
import '/pages/home/home_page.dart';
|
||||
import '/pages/login/login_page.dart';
|
||||
import '/pages/splash/splash_screen.dart';
|
||||
import '/theme/app_theme.dart';
|
||||
import 'injection_container.dart' as di;
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -19,58 +36,71 @@ void main() async {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
State<MyApp> createState() => _MyAppState();
|
||||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(create: (context) => GetIt.instance<UserCubit>()), // Добавляем UserCubit для управления пользователями
|
||||
BlocProvider(create: (context) => GetIt.instance<AuthBloc>()..add(AuthStarted())),
|
||||
BlocProvider(
|
||||
create: (context) => GetIt.instance<UserCubit>()..init(),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (context) => GetIt.instance<AuthBloc>(),
|
||||
),
|
||||
BlocProvider(create: (context) => GetIt.instance<SettingsCubit>()),
|
||||
BlocProvider(create: (context) => GetIt.instance<TransactionBloc>()),
|
||||
BlocProvider(create: (context) => GetIt.instance<SmsCubit>()),
|
||||
],
|
||||
child: BlocBuilder<SettingsCubit, SettingsState>(
|
||||
builder: (context, settingsState) {
|
||||
// Используем значения по умолчанию, если настройки не загружены
|
||||
final isDarkMode = settingsState is SettingsLoaded
|
||||
? settingsState.isDarkMode
|
||||
: false;
|
||||
final languageCode = settingsState is SettingsLoaded
|
||||
? settingsState.languageCode
|
||||
: 'ru';
|
||||
|
||||
return MaterialApp(
|
||||
title: AppLocalizations.of(context)?.appTitle ?? 'Budget App',
|
||||
theme: AppTheme.lightTheme(),
|
||||
darkTheme: AppTheme.darkTheme(),
|
||||
themeMode: isDarkMode ? ThemeMode.dark : ThemeMode.light,
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
locale: Locale(languageCode),
|
||||
home: BlocBuilder<AuthBloc, AuthState>(
|
||||
builder: (context, authState) {
|
||||
if (authState is AuthAuthenticated) {
|
||||
return const HomePage();
|
||||
} else {
|
||||
return const LoginPage();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
child: BlocListener<UserCubit, UserState>(
|
||||
listener: (context, userState) {
|
||||
if (userState is UserLoaded && userState.user != null) {
|
||||
context.read<AuthBloc>().add(AuthStarted());
|
||||
}
|
||||
},
|
||||
child: BlocBuilder<SettingsCubit, SettingsState>(
|
||||
builder: (context, settingsState) {
|
||||
final isDarkMode = settingsState is SettingsLoaded
|
||||
? settingsState.isDarkMode
|
||||
: false;
|
||||
final languageCode = settingsState is SettingsLoaded
|
||||
? settingsState.languageCode
|
||||
: 'ru';
|
||||
|
||||
return MaterialApp(
|
||||
title: AppLocalizations.of(context)?.appTitle ?? 'Budget App',
|
||||
theme: AppTheme.lightTheme(),
|
||||
darkTheme: AppTheme.darkTheme(),
|
||||
themeMode: isDarkMode ? ThemeMode.dark : ThemeMode.light,
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
locale: Locale(languageCode),
|
||||
home: BlocBuilder<UserCubit, UserState>(
|
||||
builder: (context, userState) {
|
||||
if (userState is UserLoading) {
|
||||
return const SplashScreen();
|
||||
}
|
||||
|
||||
return BlocBuilder<AuthBloc, AuthState>(
|
||||
builder: (context, authState) {
|
||||
if (authState is AuthAuthenticated) {
|
||||
return const HomePage();
|
||||
} else {
|
||||
return const LoginPage();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ class _LoginPageState extends State<LoginPage> {
|
||||
), // Локализованный заголовок
|
||||
body: BlocListener<UserCubit, UserState>(
|
||||
// Слушаем изменения состояния UserCubit
|
||||
listenWhen: (previous, current) =>
|
||||
current is UserLoaded || current is UserError,
|
||||
listener: (context, state) {
|
||||
if (state is UserLoaded && state.user != null) {
|
||||
// Комментарий: При успешном создании пользователя отправляем событие в AuthBloc
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '/logic/user/user_cubit.dart';
|
||||
|
||||
class SplashScreen extends StatelessWidget {
|
||||
const SplashScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: BlocBuilder<UserCubit, UserState>(
|
||||
builder: (context, state) {
|
||||
if (state is UserLoading) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
state.message,
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'${(state.progress * 100).toInt()}%',
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is UserError) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Ошибка загрузки',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(state.message),
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: () => context.read<UserCubit>().init(),
|
||||
child: const Text('Повторить'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user