212 lines
9.2 KiB
Dart
212 lines
9.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:drift/drift.dart' show Value;
|
|
import '../database/database.dart' as db;
|
|
import '../utils/category_utils.dart';
|
|
import '../widgets/edit_category_dialog.dart'; // Импортируем диалог
|
|
|
|
// Переименован класс SettingsScreen в CategorySettingsScreen
|
|
class CategorySettingsScreen extends StatefulWidget {
|
|
final db.AppDatabase database;
|
|
|
|
const CategorySettingsScreen({Key? key, required this.database}) : super(key: key);
|
|
|
|
@override
|
|
State<CategorySettingsScreen> createState() => _CategorySettingsScreenState();
|
|
}
|
|
|
|
// Переименован класс _SettingsScreenState в _CategorySettingsScreenState
|
|
class _CategorySettingsScreenState extends State<CategorySettingsScreen> {
|
|
late Stream<List<db.CategoryDb>> _categoriesStream;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_categoriesStream = widget.database.watchAllCategoriesDb();
|
|
}
|
|
|
|
// Функция для показа диалога добавления/редактирования
|
|
void _showEditCategoryDialog({db.CategoryDb? categoryToEdit}) async {
|
|
final result = await showDialog<bool>( // Ожидаем bool (true если сохранено)
|
|
context: context,
|
|
builder: (context) => EditCategoryDialog(
|
|
database: widget.database,
|
|
categoryToEdit: categoryToEdit, // Передаем категорию для редактирования или null для добавления
|
|
),
|
|
);
|
|
|
|
if (result == true && mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text(categoryToEdit == null ? 'Категория добавлена' : 'Категория обновлена'),
|
|
duration: const Duration(seconds: 2),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Функция для удаления категории (с подтверждением)
|
|
void _deleteCategory(db.CategoryDb category) async {
|
|
// Не позволяем удалять 'Income'
|
|
if (category.name == 'Income') {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('Категорию "Income" нельзя удалить.'),
|
|
backgroundColor: Colors.orange,
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
|
|
final confirm = await showDialog<bool>(
|
|
context: context,
|
|
builder: (context) => AlertDialog(
|
|
title: const Text('Удалить категорию?'),
|
|
content: Text('Вы уверены, что хотите удалить категорию "${category.name}"? Это действие нельзя отменить.\n\nТранзакции с этой категорией могут отображаться некорректно или вызвать ошибки при попытке их отображения, если они не будут переназначены.'),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(false), // Отмена
|
|
child: const Text('Отмена'),
|
|
),
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(true), // Подтвердить
|
|
style: TextButton.styleFrom(foregroundColor: Colors.red),
|
|
child: const Text('Удалить'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
|
|
if (confirm == true) {
|
|
try {
|
|
// Попытка удаления категории из базы данных
|
|
final deletedRows = await widget.database.deleteCategory(category.id);
|
|
|
|
if (deletedRows > 0 && mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text('Категория "${category.name}" удалена.'),
|
|
duration: const Duration(seconds: 2),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
} else if (deletedRows == 0 && mounted) {
|
|
// Это может произойти, если deleteCategory вернул 0 (например, из-за наличия транзакций)
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text('Не удалось удалить категорию "${category.name}". Возможно, она используется в транзакциях.'),
|
|
backgroundColor: Colors.red,
|
|
duration: const Duration(seconds: 3),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
}
|
|
} catch (e) {
|
|
if (mounted) {
|
|
print("Error deleting category: $e"); // Логируем ошибку
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text('Ошибка при удалении категории: ${e.toString()}'),
|
|
backgroundColor: Colors.red,
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
final isDark = theme.brightness == Brightness.dark;
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: const Text('Редактирование категорий'), // Обновленный заголовок
|
|
centerTitle: true,
|
|
backgroundColor: theme.appBarTheme.backgroundColor, // Ensure AppBar color matches theme
|
|
elevation: theme.appBarTheme.elevation, // Ensure elevation matches theme
|
|
),
|
|
body: StreamBuilder<List<db.CategoryDb>>(
|
|
stream: _categoriesStream,
|
|
builder: (context, snapshot) {
|
|
if (snapshot.connectionState == ConnectionState.waiting && !snapshot.hasData) {
|
|
return const Center(child: CircularProgressIndicator());
|
|
}
|
|
if (snapshot.hasError) {
|
|
return Center(child: Text('Ошибка загрузки категорий: ${snapshot.error}'));
|
|
}
|
|
final categories = snapshot.data ?? [];
|
|
// Фильтруем категорию 'Income', чтобы ее нельзя было редактировать/удалять отсюда
|
|
final editableCategories = categories.where((c) => c.name != 'Income').toList();
|
|
|
|
if (editableCategories.isEmpty && snapshot.connectionState != ConnectionState.waiting) {
|
|
return Center(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(20.0),
|
|
child: Text(
|
|
'Нет категорий для редактирования.\nНажмите "+", чтобы добавить новую категорию расходов.',
|
|
textAlign: TextAlign.center,
|
|
style: theme.textTheme.bodyLarge?.copyWith(color: Colors.grey),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
return ListView.separated(
|
|
padding: const EdgeInsets.symmetric(vertical: 8.0), // Add padding around the list
|
|
itemCount: editableCategories.length,
|
|
separatorBuilder: (context, index) => Divider(
|
|
height: 1,
|
|
thickness: 1,
|
|
indent: 72, // Indent to align with text after avatar
|
|
endIndent: 16,
|
|
color: theme.dividerColor.withOpacity(0.3),
|
|
),
|
|
itemBuilder: (context, index) {
|
|
final category = editableCategories[index];
|
|
final iconData = CategoryUtils.getIconFromString(category.icon);
|
|
final colorData = Color(category.color);
|
|
|
|
return ListTile(
|
|
leading: CircleAvatar(
|
|
radius: 22, // Slightly larger avatar
|
|
backgroundColor: colorData.withOpacity(isDark ? 0.3 : 0.15),
|
|
child: Icon(iconData, color: colorData, size: 24),
|
|
),
|
|
title: Text(category.name, style: theme.textTheme.titleMedium),
|
|
trailing: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
IconButton(
|
|
icon: Icon(Icons.edit_outlined, color: theme.colorScheme.primary.withOpacity(0.8)),
|
|
tooltip: 'Редактировать',
|
|
splashRadius: 24,
|
|
onPressed: () => _showEditCategoryDialog(categoryToEdit: category),
|
|
),
|
|
IconButton(
|
|
icon: Icon(Icons.delete_outline, color: Colors.red.shade400.withOpacity(0.8)),
|
|
tooltip: 'Удалить',
|
|
splashRadius: 24,
|
|
onPressed: () => _deleteCategory(category),
|
|
),
|
|
],
|
|
),
|
|
onTap: () => _showEditCategoryDialog(categoryToEdit: category), // Тоже открывает редактирование
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
floatingActionButton: FloatingActionButton(
|
|
onPressed: () => _showEditCategoryDialog(), // Вызов без аргумента для добавления
|
|
tooltip: 'Добавить категорию',
|
|
child: const Icon(Icons.add),
|
|
),
|
|
);
|
|
}
|
|
}
|