Основываясь на предоставленных изменениях, я предлагаю следующий коммит:

feat: добавить поддержку пользователей в приложение учета бюджета
This commit is contained in:
2025-06-09 22:23:52 +03:00
parent f9e95a6df5
commit c638b6ee4f
7 changed files with 238 additions and 0 deletions
@@ -41,4 +41,28 @@ class HiveCategoryRepository implements ICategoryRepository {
Future<List<Category>> getExpenseCategories() async {
return _box.values.where((c) => !c.isIncome).toList();
}
// Новые методы для работы с пользователями
@override
Future<List<Category>> getAllByUser(String userId) async {
// Фильтруем все категории по userId
return _box.values.where((c) => c.userId == userId).toList();
}
@override
Future<List<Category>> getIncomeCategoriesByUser(String userId) async {
// Получаем только категории доходов конкретного пользователя
return _box.values
.where((c) => c.userId == userId && c.isIncome)
.toList();
}
@override
Future<List<Category>> getExpenseCategoriesByUser(String userId) async {
// Получаем только категории расходов конкретного пользователя
return _box.values
.where((c) => c.userId == userId && !c.isIncome)
.toList();
}
}
@@ -0,0 +1,53 @@
import 'package:hive_ce/hive.dart';
import '/data/repositories/interfaces/iuser_repository.dart';
import '/models/user.dart';
/// Реализация репозитория пользователей с использованием Hive
/// Hive - это быстрая NoSQL база данных для Flutter
class HiveUserRepository implements IUserRepository {
final Box<User> _box; // Hive box для хранения пользователей
/// Конструктор принимает готовый Hive box
HiveUserRepository(this._box);
@override
Future<List<User>> getAll() async {
// Возвращаем все значения из box как список
return _box.values.toList();
}
@override
Future<User?> getById(String id) async {
// Получаем пользователя по ключу (id)
return _box.get(id);
}
@override
Future<User?> getByEmail(String email) async {
// Ищем пользователя по email среди всех пользователей
try {
return _box.values.firstWhere((user) => user.email == email);
} catch (e) {
// Если пользователь не найден, возвращаем null
return null;
}
}
@override
Future<void> add(User user) async {
// Сохраняем пользователя с его id как ключом
await _box.put(user.id, user);
}
@override
Future<void> update(User user) async {
// Обновление = перезапись существующего пользователя
await add(user);
}
@override
Future<void> delete(String id) async {
// Удаляем пользователя по id
await _box.delete(id);
}
}
@@ -1,6 +1,7 @@
import '/models/category.dart';
abstract class ICategoryRepository {
// Старые методы для обратной совместимости
Future<List<Category>> getAll();
Future<Category?> getById(String id);
Future<void> add(Category category);
@@ -8,4 +9,14 @@ abstract class ICategoryRepository {
Future<void> delete(String id);
Future<List<Category>> getIncomeCategories();
Future<List<Category>> getExpenseCategories();
// Новые методы для работы с пользователями
/// Получить все категории конкретного пользователя
Future<List<Category>> getAllByUser(String userId);
/// Получить категории доходов конкретного пользователя
Future<List<Category>> getIncomeCategoriesByUser(String userId);
/// Получить категории расходов конкретного пользователя
Future<List<Category>> getExpenseCategoriesByUser(String userId);
}
@@ -0,0 +1,23 @@
import '/models/user.dart';
/// Интерфейс для работы с пользователями в базе данных
/// Определяет основные операции CRUD (Create, Read, Update, Delete)
abstract class IUserRepository {
/// Получить всех пользователей
Future<List<User>> getAll();
/// Получить пользователя по ID
Future<User?> getById(String id);
/// Получить пользователя по email (для входа в систему)
Future<User?> getByEmail(String email);
/// Добавить нового пользователя
Future<void> add(User user);
/// Обновить существующего пользователя
Future<void> update(User user);
/// Удалить пользователя
Future<void> delete(String id);
}
+8
View File
@@ -31,6 +31,11 @@ class Category {
/// false - расход (например покупки)
final bool isIncome;
@HiveField(5)
/// Идентификатор пользователя, которому принадлежит эта категория
/// Это позволяет разделять категории между разными пользователями
final String userId;
/// Конструктор с обязательными параметрами
Category({
String? id,
@@ -38,6 +43,7 @@ class Category {
required this.color,
required this.icon,
required this.isIncome,
required this.userId, // Теперь userId обязательный параметр
}) : id = id ?? IdGenerator.generateId();
/// Метод для преобразования объекта в Map (полезно для работы с БД)
@@ -48,6 +54,7 @@ class Category {
'color': color.value, // Сохраняем только значение цвета
'icon': icon.codePoint,
'isIncome': isIncome,
'userId': userId, // Добавляем userId в Map
};
}
@@ -59,6 +66,7 @@ class Category {
color: Color(map['color']),
icon: IconData(map['icon'], fontFamily: 'MaterialIcons'),
isIncome: map['isIncome'],
userId: map['userId'], // Добавляем userId при создании из Map
);
}
}
+55
View File
@@ -0,0 +1,55 @@
import 'package:hive_ce/hive.dart';
import '../utils/id_generator.dart';
// Указываем Hive, что это модель для хранения в базе данных
// typeId: 3 - уникальный идентификатор типа для Hive (у нас уже есть 0,1,2)
part 'user.g.dart';
@HiveType(typeId: 3)
/// Модель пользователя приложения
/// Содержит основную информацию для идентификации пользователя
class User {
/// Уникальный идентификатор пользователя
@HiveField(0) // Поле 0 в Hive - первое поле модели
final String id;
/// Имя пользователя для отображения в интерфейсе
@HiveField(1) // Поле 1 в Hive - второе поле модели
final String name;
/// Email пользователя (может использоваться для входа в будущем)
@HiveField(2) // Поле 2 в Hive - третье поле модели
final String email;
/// Конструктор пользователя
/// id генерируется автоматически, если не передан
User({
String? id, // Опциональный параметр - если null, сгенерируется автоматически
required this.name, // Обязательный параметр
required this.email, // Обязательный параметр
}) : id = id ?? IdGenerator.generateId(); // Если id не передан, генерируем новый
/// Преобразование объекта в Map для сохранения в JSON или передачи по сети
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'email': email,
};
}
/// Создание объекта User из Map (например, при загрузке из JSON)
factory User.fromMap(Map<String, dynamic> map) {
return User(
id: map['id'],
name: map['name'],
email: map['email'],
);
}
/// Переопределяем toString для удобного отображения в логах
@override
String toString() {
return 'User(id: $id, name: $name, email: $email)';
}
}
+64
View File
@@ -0,0 +1,64 @@
import 'package:flutter/foundation.dart';
import 'package:hive_ce/hive.dart';
import '/models/user.dart';
import '/data/repositories/interfaces/iuser_repository.dart';
/// Сервис для управления текущим пользователем приложения
/// Использует ChangeNotifier для уведомления UI об изменениях
class UserService extends ChangeNotifier {
// Ключ для сохранения ID текущего пользователя в настройках
static const String _currentUserKey = 'currentUserId';
late final Box _settingsBox; // Box для хранения настроек
final IUserRepository _userRepository; // Репозиторий для работы с пользователями
User? _currentUser; // Текущий активный пользователь
/// Геттер для получения текущего пользователя
User? get currentUser => _currentUser;
/// Проверяем, есть ли активный пользователь
bool get hasCurrentUser => _currentUser != null;
/// Конструктор сервиса
UserService(this._userRepository) {
_settingsBox = Hive.box('settings');
_loadCurrentUser(); // Загружаем сохраненного пользователя при запуске
}
/// Загружаем текущего пользователя из настроек
Future<void> _loadCurrentUser() async {
final userId = _settingsBox.get(_currentUserKey);
if (userId != null) {
_currentUser = await _userRepository.getById(userId);
notifyListeners(); // Уведомляем UI об изменении
}
}
/// Устанавливаем текущего пользователя
Future<void> setCurrentUser(User user) async {
_currentUser = user;
// Сохраняем ID пользователя в настройках для следующего запуска
await _settingsBox.put(_currentUserKey, user.id);
notifyListeners(); // Уведомляем UI об изменении
}
/// Выход из аккаунта (сброс текущего пользователя)
Future<void> logout() async {
_currentUser = null;
await _settingsBox.delete(_currentUserKey);
notifyListeners(); // Уведомляем UI об изменении
}
/// Создание нового пользователя и установка его как текущего
Future<void> createAndSetUser(String name, String email) async {
final user = User(name: name, email: email);
await _userRepository.add(user);
await setCurrentUser(user);
}
/// Получение всех пользователей (для выбора)
Future<List<User>> getAllUsers() async {
return await _userRepository.getAll();
}
}