Files
BudgetApp/lib/logic/user/user_cubit.dart
T
2025-07-07 18:11:03 +03:00

193 lines
7.5 KiB
Dart

import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:flutter/foundation.dart';
import 'package:logger/logger.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 для управления состоянием пользователя
class UserCubit extends Cubit<UserState> {
final IGlobalSettingsRepository _settingsRepository;
final IUserRepository _userRepository;
final ICategoryRepository _categoryRepository;
final ITagRepository _tagRepository;
final ITransactionRepository _transactionRepository;
final Logger _logger = Logger();
UserCubit({
required IGlobalSettingsRepository settingsRepository,
required IUserRepository userRepository,
required ICategoryRepository categoryRepository,
required ITagRepository tagRepository,
required ITransactionRepository transactionRepository,
}) : _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(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) {
_logger.w('User with ID $userId not found. Clearing key.');
await _settingsRepository.setCurrentUserId(null);
}
}
// Этап 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');
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);
emit(UserError('Ошибка загрузки пользователя: ${e.toString()}'));
}
}
Future<User> _createDefaultUser() async {
final user = User(
name: 'Пользователь по умолчанию',
email: 'default@example.com',
);
await _userRepository.add(user);
// Создаем начальные данные для нового пользователя
await _createInitialData(user.id);
await _setCurrentUser(user);
return user;
}
Future<void> _createInitialData(String userId) async {
try {
// Разбиваем создание данных на этапы
emit(UserLoading(progress: 0.7, message: 'Создание категорий...'));
await _categoryRepository.addAll(
CategoryUtils.getDefaultCategories(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,
);
}
}
Future<void> _setCurrentUser(User user) async {
await _settingsRepository.setCurrentUserId(user.id);
emit(UserLoaded(user));
}
/// Устанавливает текущего пользователя
Future<void> setCurrentUser(User user) async {
emit(UserLoading());
try {
await _setCurrentUser(user);
} catch (e, stack) {
_logger.e('Error setting current user', error: e, stackTrace: stack);
emit(UserError('Ошибка установки пользователя: ${e.toString()}'));
}
}
/// Устанавливает текущего пользователя (прямая установка без загрузки)
void setUser(User user) {
emit(UserLoaded(user));
}
/// Выход из системы
Future<void> logout() async {
emit(UserLoading());
try {
await _settingsRepository.setCurrentUserId(null);
emit(UserLoaded(null));
} catch (e, stack) {
_logger.e('Error during logout', error: e, stackTrace: stack);
emit(UserError('Ошибка выхода из системы: ${e.toString()}'));
}
}
/// Создает нового пользователя и устанавливает его как текущего
Future<void> createAndSetUser(String name, String email) async {
emit(UserLoading());
try {
final user = User(name: name, email: email);
await _userRepository.add(user);
// Создаем начальные данные для нового пользователя
await _createInitialData(user.id);
await _setCurrentUser(user);
} catch (e, stack) {
_logger.e('Error creating user', error: e, stackTrace: stack);
emit(UserError('Ошибка создания пользователя: ${e.toString()}'));
}
}
/// Возвращает всех пользователей
Future<List<User>> getAllUsers() async {
try {
return await _userRepository.getAll();
} catch (e, stack) {
_logger.e('Error getting all users', error: e, stackTrace: stack);
return [];
}
}
}