Add bloc
This commit is contained in:
@@ -6,7 +6,12 @@ import 'data/repositories/hive_transaction_repository.dart';
|
||||
import 'data/repositories/interfaces/icategory_repository.dart';
|
||||
import 'data/repositories/interfaces/itag_repository.dart';
|
||||
import 'data/repositories/interfaces/itransaction_repository.dart';
|
||||
import 'data/repositories/hive_user_repository.dart';
|
||||
import 'data/repositories/interfaces/iuser_repository.dart';
|
||||
import 'logic/auth/auth_bloc.dart';
|
||||
import 'logic/transaction/transaction_bloc.dart';
|
||||
import 'services/settings_service.dart';
|
||||
import 'services/user_service.dart';
|
||||
|
||||
final getIt = GetIt.instance;
|
||||
|
||||
@@ -29,4 +34,15 @@ Future<void> initDependencies() async {
|
||||
getIt.registerSingleton<ITransactionRepository>(
|
||||
HiveTransactionRepository(HiveService.transactions),
|
||||
);
|
||||
|
||||
getIt.registerSingleton<IUserRepository>(
|
||||
HiveUserRepository(HiveService.users),
|
||||
);
|
||||
|
||||
// Services
|
||||
getIt.registerSingleton<UserService>(UserService(getIt()));
|
||||
|
||||
// Blocs
|
||||
getIt.registerFactory<AuthBloc>(() => AuthBloc(userService: getIt()));
|
||||
getIt.registerFactory<TransactionBloc>(() => TransactionBloc(transactionRepository: getIt()));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:budget_app/models/user.dart';
|
||||
import 'package:budget_app/services/user_service.dart';
|
||||
|
||||
part 'auth_event.dart';
|
||||
part 'auth_state.dart';
|
||||
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final UserService _userService;
|
||||
|
||||
AuthBloc({required UserService userService}) : _userService = userService, super(AuthInitial()) {
|
||||
on<AuthStarted>(_onAuthStarted);
|
||||
on<AuthLoggedIn>(_onAuthLoggedIn);
|
||||
on<AuthLoggedOut>(_onAuthLoggedOut);
|
||||
}
|
||||
|
||||
void _onAuthStarted(AuthStarted event, Emitter<AuthState> emit) {
|
||||
final user = _userService.currentUser;
|
||||
if (user != null) {
|
||||
emit(AuthAuthenticated(user: user));
|
||||
} else {
|
||||
emit(AuthUnauthenticated());
|
||||
}
|
||||
}
|
||||
|
||||
void _onAuthLoggedIn(AuthLoggedIn event, Emitter<AuthState> emit) {
|
||||
emit(AuthAuthenticated(user: event.user));
|
||||
}
|
||||
|
||||
void _onAuthLoggedOut(AuthLoggedOut event, Emitter<AuthState> emit) {
|
||||
_userService.logout();
|
||||
emit(AuthUnauthenticated());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
part of 'auth_bloc.dart';
|
||||
|
||||
abstract class AuthEvent extends Equatable {
|
||||
const AuthEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
// Событие, которое будет вызываться при инициализации BLoC
|
||||
class AuthStarted extends AuthEvent {}
|
||||
|
||||
// Событие, которое будет вызываться при входе пользователя
|
||||
class AuthLoggedIn extends AuthEvent {
|
||||
final User user;
|
||||
|
||||
const AuthLoggedIn({required this.user});
|
||||
|
||||
@override
|
||||
List<Object> get props => [user];
|
||||
}
|
||||
|
||||
// Событие, которое будет вызываться при выходе пользователя
|
||||
class AuthLoggedOut extends AuthEvent {}
|
||||
@@ -0,0 +1,24 @@
|
||||
part of 'auth_bloc.dart';
|
||||
|
||||
abstract class AuthState extends Equatable {
|
||||
const AuthState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
// Начальное состояние, пока мы не знаем, аутентифицирован ли пользователь
|
||||
class AuthInitial extends AuthState {}
|
||||
|
||||
// Состояние, когда пользователь аутентифицирован
|
||||
class AuthAuthenticated extends AuthState {
|
||||
final User user;
|
||||
|
||||
const AuthAuthenticated({required this.user});
|
||||
|
||||
@override
|
||||
List<Object> get props => [user];
|
||||
}
|
||||
|
||||
// Состояние, когда пользователь не аутентифицирован
|
||||
class AuthUnauthenticated extends AuthState {}
|
||||
@@ -0,0 +1,67 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:budget_app/data/repositories/interfaces/itransaction_repository.dart';
|
||||
import 'package:budget_app/models/transaction_record.dart';
|
||||
|
||||
part 'transaction_event.dart';
|
||||
part 'transaction_state.dart';
|
||||
|
||||
class TransactionBloc extends Bloc<TransactionEvent, TransactionState> {
|
||||
final ITransactionRepository _transactionRepository;
|
||||
|
||||
TransactionBloc({required ITransactionRepository transactionRepository})
|
||||
: _transactionRepository = transactionRepository,
|
||||
super(TransactionInitial()) {
|
||||
on<LoadTransactions>(_onLoadTransactions);
|
||||
on<AddTransaction>(_onAddTransaction);
|
||||
on<UpdateTransaction>(_onUpdateTransaction);
|
||||
on<DeleteTransaction>(_onDeleteTransaction);
|
||||
}
|
||||
|
||||
void _onLoadTransactions(LoadTransactions event, Emitter<TransactionState> emit) async {
|
||||
emit(TransactionLoading());
|
||||
try {
|
||||
final transactions = await _transactionRepository.getAllByUser(event.userId);
|
||||
emit(TransactionLoaded(transactions: transactions));
|
||||
} catch (e) {
|
||||
emit(TransactionError(message: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void _onAddTransaction(AddTransaction event, Emitter<TransactionState> emit) async {
|
||||
try {
|
||||
await _transactionRepository.add(event.transaction);
|
||||
final transactions = await _transactionRepository.getAllByUser(event.transaction.userId);
|
||||
emit(TransactionLoaded(transactions: transactions));
|
||||
} catch (e) {
|
||||
emit(TransactionError(message: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void _onUpdateTransaction(UpdateTransaction event, Emitter<TransactionState> emit) async {
|
||||
try {
|
||||
await _transactionRepository.update(event.transaction);
|
||||
final transactions = await _transactionRepository.getAllByUser(event.transaction.userId);
|
||||
emit(TransactionLoaded(transactions: transactions));
|
||||
} catch (e) {
|
||||
emit(TransactionError(message: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void _onDeleteTransaction(DeleteTransaction event, Emitter<TransactionState> emit) async {
|
||||
try {
|
||||
// Для удаления нам нужен userId, который мы можем получить из текущего состояния
|
||||
if (state is TransactionLoaded) {
|
||||
final loadedState = state as TransactionLoaded;
|
||||
if (loadedState.transactions.isNotEmpty) {
|
||||
final userId = loadedState.transactions.first.userId;
|
||||
await _transactionRepository.delete(event.transactionId);
|
||||
final transactions = await _transactionRepository.getAllByUser(userId);
|
||||
emit(TransactionLoaded(transactions: transactions));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
emit(TransactionError(message: e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
part of 'transaction_bloc.dart';
|
||||
|
||||
abstract class TransactionEvent extends Equatable {
|
||||
const TransactionEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class LoadTransactions extends TransactionEvent {
|
||||
final String userId;
|
||||
|
||||
const LoadTransactions({required this.userId});
|
||||
|
||||
@override
|
||||
List<Object> get props => [userId];
|
||||
}
|
||||
|
||||
class AddTransaction extends TransactionEvent {
|
||||
final TransactionRecord transaction;
|
||||
|
||||
const AddTransaction({required this.transaction});
|
||||
|
||||
@override
|
||||
List<Object> get props => [transaction];
|
||||
}
|
||||
|
||||
class UpdateTransaction extends TransactionEvent {
|
||||
final TransactionRecord transaction;
|
||||
|
||||
const UpdateTransaction({required this.transaction});
|
||||
|
||||
@override
|
||||
List<Object> get props => [transaction];
|
||||
}
|
||||
|
||||
class DeleteTransaction extends TransactionEvent {
|
||||
final String transactionId;
|
||||
|
||||
const DeleteTransaction({required this.transactionId});
|
||||
|
||||
@override
|
||||
List<Object> get props => [transactionId];
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
part of 'transaction_bloc.dart';
|
||||
|
||||
abstract class TransactionState extends Equatable {
|
||||
const TransactionState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class TransactionInitial extends TransactionState {}
|
||||
|
||||
class TransactionLoading extends TransactionState {}
|
||||
|
||||
class TransactionLoaded extends TransactionState {
|
||||
final List<TransactionRecord> transactions;
|
||||
|
||||
const TransactionLoaded({this.transactions = const []});
|
||||
|
||||
@override
|
||||
List<Object> get props => [transactions];
|
||||
}
|
||||
|
||||
class TransactionError extends TransactionState {
|
||||
final String message;
|
||||
|
||||
const TransactionError({required this.message});
|
||||
|
||||
@override
|
||||
List<Object> get props => [message];
|
||||
}
|
||||
+31
-9
@@ -1,4 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'logic/auth/auth_bloc.dart';
|
||||
import 'package:budget_app/pages/home_page.dart';
|
||||
import 'theme/app_theme.dart';
|
||||
import 'package:hive_ce_flutter/hive_flutter.dart';
|
||||
@@ -12,19 +14,26 @@ void main() async {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
/// Главный виджет приложения
|
||||
///
|
||||
/// Управляет:
|
||||
/// - Состоянием темы (темная/светлая)
|
||||
/// - Конфигурацией MaterialApp
|
||||
class MyApp extends StatefulWidget {
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
State<MyApp> createState() => _MyAppState();
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => GetIt.instance<AuthBloc>()..add(AuthStarted()),
|
||||
child: const AppView(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> {
|
||||
class AppView extends StatefulWidget {
|
||||
const AppView({super.key});
|
||||
|
||||
@override
|
||||
State<AppView> createState() => _AppViewState();
|
||||
}
|
||||
|
||||
class _AppViewState extends State<AppView> {
|
||||
late final SettingsService _settingsService;
|
||||
|
||||
@override
|
||||
@@ -51,7 +60,20 @@ class _MyAppState extends State<MyApp> {
|
||||
theme: AppTheme.lightTheme(),
|
||||
darkTheme: AppTheme.darkTheme(),
|
||||
themeMode: _settingsService.isDarkMode ? ThemeMode.dark : ThemeMode.light,
|
||||
home: const HomePage(),
|
||||
home: BlocBuilder<AuthBloc, AuthState>(
|
||||
builder: (context, state) {
|
||||
if (state is AuthAuthenticated) {
|
||||
return const HomePage();
|
||||
} else {
|
||||
// Здесь будет страница входа, пока просто заглушка
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: Text('Требуется аутентификация'),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.13.0"
|
||||
bloc:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bloc
|
||||
sha256: "52c10575f4445c61dd9e0cafcc6356fdd827c4c64dd7945ef3c4105f6b6ac189"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.0.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -177,6 +185,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
equatable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: equatable
|
||||
sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.7"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -214,6 +230,14 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_bloc:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_bloc
|
||||
sha256: cf51747952201a455a1c840f8171d273be009b932c75093020f9af64f2123e38
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.1.1"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -419,6 +443,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nested
|
||||
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -507,6 +539,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: provider
|
||||
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.5"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -40,6 +40,9 @@ dependencies:
|
||||
path_provider: ^2.0.15
|
||||
uuid: ^3.0.7
|
||||
logger: ^2.5.0
|
||||
flutter_bloc: ^9.1.1
|
||||
equatable: ^2.0.7
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
hive_ce_generator: ^1.9.2
|
||||
|
||||
Reference in New Issue
Block a user