Files
BudgetApp/lib/pages/settings_page.dart
T
Sanders 8b75299d41 Refactors data repositories for single-user mode
This commit refactors the data repositories to remove user-specific filtering. It simplifies the data access logic by retrieving all data from the Hive boxes and removing the need to filter by `userId` in the repository methods.

This change makes the app function in single-user mode and removes the need to manage multiple user contexts within the data layer.

Specifically:
- Removes `userId` parameter from repository methods.
- Updates the setting repository to use fixed keys.
- Removes user ID filtering from queries.
- Removes user ID parameters from Cubits and Blocs
- Updates initial data creation
2025-07-12 21:54:00 +03:00

181 lines
10 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:budget_app/logic/sms/sms_cubit.dart';
import 'package:budget_app/pages/category/category_list_page.dart';
import 'package:budget_app/pages/tag/tag_list_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '/l10n/app_localizations.dart';
import '../logic/settings/settings_cubit.dart';
import '../logic/user/user_cubit.dart';
// Комментарий: Мы преобразуем SettingsPage из StatefulWidget в StatelessWidget.
// Это возможно, потому что теперь состояние управляется SettingsCubit,
// и виджету не нужно хранить собственное состояние, что делает код проще и эффективнее.
class SettingsPage extends StatelessWidget {
const SettingsPage({super.key});
@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
title: Text(localizations.settingsPageTitle),
),
body: BlocListener<SettingsCubit, SettingsState>(
listener: (context, state) {
// Комментарий: Обрабатываем ошибки и показываем SnackBar пользователю
if (state is SettingsError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Ошибка настроек: ${state.message}'),
backgroundColor: Theme.of(context).colorScheme.error,
),
);
}
},
child: BlocBuilder<UserCubit, UserState>(
builder: (context, userState) {
if (userState is UserLoaded && userState.user != null) {
// Комментарий: Как только пользователь загружен, мы загружаем его настройки.
context.read<SettingsCubit>().loadSettings();
return BlocBuilder<SettingsCubit, SettingsState>(
builder: (context, state) {
if (state is SettingsLoaded) {
return Padding(
padding: const EdgeInsets.all(16.0),
// Комментарий: Обернули Column в SingleChildScrollView, чтобы избежать переполнения по вертикали.
// Это позволяет прокручивать содержимое, если оно не помещается на экране.
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SwitchListTile(
title: Text(localizations.darkModeSetting),
subtitle: Text(localizations.darkModeDescription),
value: state.isDarkMode,
// Комментарий: При изменении положения переключателя (onChanged) мы вызываем метод `toggleDarkMode` у Cubit.
// `context.read<SettingsCubit>()` используется для доступа к Cubit без подписки на его изменения.
// Это хорошо для вызова методов. Также передаем userId из UserService.
onChanged: (value) {
// Получаем ID текущего пользователя из UserCubit
context
.read<SettingsCubit>()
.toggleDarkMode(value);
},
),
const Divider(),
ListTile(
title: Text(localizations.languageSetting),
subtitle: Text(localizations.languageDescription),
trailing: DropdownButton<String>(
value: state.languageCode,
// Комментарий: При выборе нового языка вызываем метод `changeLanguage` у Cubit.
// Также передаем userId из UserService.
onChanged: (String? newValue) {
if (newValue != null) {
context
.read<SettingsCubit>()
.changeLanguage(newValue);
}
},
// Комментарий: Формируем список доступных языков.
items: <String>['en', 'ru']
.map<DropdownMenuItem<String>>(
(String value) {
return DropdownMenuItem<String>(
value: value,
// Комментарий: Отображаем локализованное название языка.
child: Text(value == 'en'
? localizations.englishLanguage
: localizations.russianLanguage),
);
}).toList(),
),
),
const Divider(),
ListTile(
title: Text(localizations.currencySetting),
subtitle: Text(localizations.currencyDescription),
trailing: DropdownButton<String>(
value: state.defaultCurrency,
// Комментарий: При выборе новой валюты вызываем метод `changeCurrency` у Cubit.
// Также передаем userId из UserService.
onChanged: (String? newValue) {
if (newValue != null) {
context
.read<SettingsCubit>()
.changeCurrency(newValue);
}
},
// Комментарий: Формируем список доступных валют. Можно расширить этот список.
items: <String>['RUB', 'USD', 'EUR']
.map<DropdownMenuItem<String>>(
(String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
const Divider(),
// Комментарий: ListTile для перехода на страницу редактирования категорий.
ListTile(
title: Text(localizations.editCategories),
subtitle:
Text(localizations.editCategoriesDescription),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const CategoryListPage(),
),
);
},
),
const Divider(),
ListTile(
title: Text(localizations.editTags),
subtitle: Text(localizations.editTagsDescription),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const TagListPage(),
),
);
},
),
const Divider(),
// Комментарий: ListTile для запуска процесса загрузки SMS-сообщений.
ListTile(
title: Text(localizations.loadSmsMessages),
subtitle:
Text(localizations.loadSmsMessagesDescription),
onTap: () {
// Комментарий: При нажатии на кнопку мы вызываем метод `loadSmsMessages` у SmsCubit.
// Это инициирует процесс получения и сохранения SMS-сообщений.
context.read<SmsCubit>().loadSmsMessages();
},
),
const Divider(),
],
),
),
);
} else {
return const Center(child: CircularProgressIndicator());
}
},
);
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
),
);
}
}