Adds category management feature

Adds the ability to manage categories in the settings page. This includes:
- Registers CategoryCubit in the dependency injection container.
- Introduces a new CategoryListPage for editing categories.
- Adds translations for category management related text.
- Adds unselected icon color to the theme.
- Updates the date format in the transaction dialog.
This commit is contained in:
2025-06-30 15:59:43 +03:00
parent 829ca93d9b
commit 6da0da45b7
17 changed files with 661 additions and 32 deletions
-28
View File
@@ -1,28 +0,0 @@
# Project: Budget App
## General Instructions:
- Это проект на Flutter используй только его
- Комментируй в коде каждое изменение, которое ты делаешь, что бы мне было понятно и я учился на этом.
- Комментарии и твои ответы должны быть на русском языке
- When generating new Flutter code, please follow the existing coding style.
- Цветовая палитра черно-белая
- Все настройки цветов выноси в тему
- Все элементы должны разбиваться на мелкие и иметь логичную структуру по попкам
- Весь текст должен иметь локализацию чрезе flutter_localizations. Смотри папку l10n
- Разработка ведется под windows, ты можешь исопльзовать его консольные команды
## Coding Style:
- Interface names should be prefixed with `I` (e.g., `IUserService`).
- Private class members should be prefixed with an underscore (`_`).
- Учитывай, что в проекте используется bloc cubit архитектура
## Role
- You are a Flutter assistant that helps users write more efficient and optimizable Flutter code.
- You specialize in identifying patterns that enable Flutter Compiler to automatically apply optimizations, reducing unnecessary re-renders and improving application performance.
## Follow these guidelines in all code you produce and suggest
- Prefer composition and small components: Break down UI into small, reusable components rather than writing large monolithic components. The code you generate should promote clarity and reusability by composing components together.
- Design for a good user experience - Provide clear, minimal, and non-blocking UI states. When data is loading, show lightweight placeholders (e.g., skeleton screens) rather than intrusive spinners everywhere. Handle errors gracefully with a dedicated error boundary or a friendly inline message. Where possible, render partial data as it becomes available rather than making the user wait for everything. Suspense allows you to declare the loading states in your component tree in a natural way, preventing “flash” states and improving perceived performance.
-
+4
View File
@@ -10,6 +10,7 @@ import 'data/repositories/interfaces/itag_repository.dart';
import 'data/repositories/interfaces/itransaction_repository.dart';
import 'data/repositories/interfaces/iuser_repository.dart';
import 'logic/auth/auth_bloc.dart';
import 'logic/category/category_cubit.dart';
import 'logic/settings/settings_cubit.dart'; // Импортируем SettingsCubit
import 'logic/sms/sms_cubit.dart';
import 'logic/transaction/transaction_bloc.dart';
@@ -56,4 +57,7 @@ Future<void> initDependencies() async {
);
getIt.registerFactory<SmsCubit>(() => SmsCubit(getIt()));
getIt.registerFactory<CategoryCubit>(
() => CategoryCubit(getIt()),
); // Регистрируем CategoryCubit с зависимостью от UserService
}
+6 -1
View File
@@ -37,5 +37,10 @@
"save": "Save",
"tag": "Tag",
"smsPageTitle": "SMS Messages",
"smsPermissionDenied": "SMS permission is required"
"smsPermissionDenied": "SMS permission is required",
"editCategories": "Edit Categories",
"editCategoriesDescription": "Add, edit, or delete categories",
"color": "Color",
"chooseIcon": "Pick icon",
"chooseIconHint": "Search"
}
+30
View File
@@ -325,6 +325,36 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'SMS permission is required'**
String get smsPermissionDenied;
/// No description provided for @editCategories.
///
/// In en, this message translates to:
/// **'Edit Categories'**
String get editCategories;
/// No description provided for @editCategoriesDescription.
///
/// In en, this message translates to:
/// **'Add, edit, or delete categories'**
String get editCategoriesDescription;
/// No description provided for @color.
///
/// In en, this message translates to:
/// **'Color'**
String get color;
/// No description provided for @chooseIcon.
///
/// In en, this message translates to:
/// **'Pick icon'**
String get chooseIcon;
/// No description provided for @chooseIconHint.
///
/// In en, this message translates to:
/// **'Search'**
String get chooseIconHint;
}
class _AppLocalizationsDelegate
+15
View File
@@ -123,4 +123,19 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get smsPermissionDenied => 'SMS permission is required';
@override
String get editCategories => 'Edit Categories';
@override
String get editCategoriesDescription => 'Add, edit, or delete categories';
@override
String get color => 'Color';
@override
String get chooseIcon => 'Pick icon';
@override
String get chooseIconHint => 'Search';
}
+16
View File
@@ -124,4 +124,20 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get smsPermissionDenied => 'Необходимо разрешение на чтение SMS';
@override
String get editCategories => 'Редактировать категории';
@override
String get editCategoriesDescription =>
'Добавляйте, редактируйте или удаляйте категории';
@override
String get color => 'Цвет';
@override
String get chooseIcon => 'Выберите иконку';
@override
String get chooseIconHint => 'Поиск по анлгийскому наименованию';
}
+6 -1
View File
@@ -37,5 +37,10 @@
"save": "Сохранить",
"tag": "Тег",
"smsPageTitle": "SMS Сообщения",
"smsPermissionDenied": "Необходимо разрешение на чтение SMS"
"smsPermissionDenied": "Необходимо разрешение на чтение SMS",
"editCategories": "Редактировать категории",
"editCategoriesDescription": "Добавляйте, редактируйте или удаляйте категории",
"color": "Цвет",
"chooseIcon": "Выберите иконку",
"chooseIconHint": "Поиск по анлгийскому наименованию"
}
+49
View File
@@ -0,0 +1,49 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:budget_app/models/category.dart';
import 'package:hive_ce/hive.dart';
import 'package:budget_app/services/user_service.dart'; // Импортируем UserService
class CategoryCubit extends Cubit<List<Category>> {
final UserService _userService; // Добавляем зависимость от UserService
final Box<Category> _categoryBox; // Используем Box<Category> для типизации
CategoryCubit(this._userService) // Принимаем UserService через конструктор
: _categoryBox = Hive.box<Category>('categories'),
super([]);
// Загружает категории, фильтруя их по userId текущего пользователя
void loadCategories() {
final currentUserId = _userService.currentUser?.id;
if (currentUserId != null) {
final userCategories = _categoryBox.values
.where((category) => category.userId == currentUserId)
.toList();
emit(List.from(userCategories));
} else {
emit([]); // Если пользователя нет, список категорий пуст
}
}
// Добавляет новую категорию, присваивая ей userId текущего пользователя
void addCategory(Category category) {
final currentUserId = _userService.currentUser?.id;
if (currentUserId != null) {
final newCategory = category.copyWith(userId: currentUserId); // Присваиваем userId
_categoryBox.put(newCategory.id, newCategory);
loadCategories();
}
}
// Обновляет существующую категорию
void updateCategory(Category category) {
_categoryBox.put(category.id, category);
loadCategories();
}
// Удаляет категорию по ее id
void deleteCategory(String id) {
_categoryBox.delete(id);
loadCategories();
}
}
+167
View File
@@ -0,0 +1,167 @@
import 'package:budget_app/l10n/app_localizations.dart';
import 'package:budget_app/models/category.dart';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:flutter_iconpicker/Models/configuration.dart';
import 'package:flutter_iconpicker/flutter_iconpicker.dart';
class CategoryEditPage extends StatefulWidget {
final Category? category;
final Function(String, Color, IconData) onSave;
const CategoryEditPage({super.key, this.category, required this.onSave});
@override
_CategoryEditPageState createState() => _CategoryEditPageState();
}
class _CategoryEditPageState extends State<CategoryEditPage> {
final _formKey = GlobalKey<FormState>();
late String _name;
late Color _color;
late IconData _icon;
@override
void initState() {
super.initState();
_name = widget.category?.name ?? '';
_color = widget.category?.color ?? Colors.blue;
_icon = widget.category?.icon ?? Icons.ac_unit;
}
@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
title: Text(
widget.category == null
? localizations.addTransactionButton
: localizations.editCategories,
),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
initialValue: _name,
decoration: InputDecoration(
labelText: localizations.nameFieldLabel,
),
validator: (value) {
if (value == null || value.isEmpty) {
return localizations.nameFieldEmptyError;
}
return null;
},
onSaved: (value) {
_name = value!;
},
),
const SizedBox(height: 20),
Row(
children: [
Text(localizations.color),
const SizedBox(width: 10),
GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(localizations.color),
content: SingleChildScrollView(
child: ColorPicker(
pickerColor: _color,
onColorChanged: (color) {
setState(() {
_color = color;
});
},
),
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(localizations.save),
),
],
),
);
},
child: CircleAvatar(backgroundColor: _color),
),
],
),
const SizedBox(height: 20),
Row(
children: [
Text(localizations.tag),
const SizedBox(width: 10),
GestureDetector(
onTap: () async {
final icon = await showIconPicker(
context,
configuration: SinglePickerConfiguration(
adaptiveDialog: true,
showTooltips: true,
showSearchBar: true,
preSelected: IconPickerIcon(
name: '',
data: _icon,
pack: IconPack.material,
),
title: Text(
localizations.chooseIcon,
textScaler: const TextScaler.linear(1.25),
),
searchHintText: localizations.chooseIconHint,
iconPickerShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
//iconPackModes: IconNotifier.starterPacks,
searchComparator:
(String search, IconPickerIcon icon) =>
search.toLowerCase().contains(
icon.name
.replaceAll('_', ' ')
.toLowerCase(),
) ||
icon.name.toLowerCase().contains(
search.toLowerCase(),
),
),
);
if (icon != null) {
setState(() {
_icon = icon.data;
});
}
},
child: Icon(_icon),
),
],
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
widget.onSave(_name, _color, _icon);
Navigator.pop(context);
}
},
child: Text(localizations.save),
),
],
),
),
),
);
}
}
+100
View File
@@ -0,0 +1,100 @@
import 'package:budget_app/l10n/app_localizations.dart';
import 'package:budget_app/logic/category/category_cubit.dart';
import 'package:budget_app/models/category.dart';
import 'package:budget_app/pages/category/category_edit_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart'; // Импортируем GetIt
class CategoryListPage extends StatelessWidget {
const CategoryListPage({super.key});
@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(title: Text(localizations.editCategories)),
body: BlocProvider(
create: (context) =>
GetIt.instance<CategoryCubit>()
..loadCategories(), // Получаем CategoryCubit из GetIt
child: BlocBuilder<CategoryCubit, List<Category>>(
builder: (context, categories) {
return ListView.builder(
itemCount: categories.length,
itemBuilder: (context, index) {
final category = categories[index];
return ListTile(
leading: CircleAvatar(
backgroundColor: category.color,
child: Icon(category.icon, color: Colors.white),
),
title: Text(category.name),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => CategoryEditPage(
category: category,
onSave: (name, color, icon) {
final updatedCategory = category.copyWith(
name: name,
color: color,
icon: icon,
);
context.read<CategoryCubit>().updateCategory(
updatedCategory,
); // Обновляем категорию по ее id
},
),
),
);
},
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
context.read<CategoryCubit>().deleteCategory(
category.id,
); // Удаляем категорию по ее id
},
),
],
),
);
},
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => CategoryEditPage(
onSave: (name, color, icon) {
final newCategory = Category(
name: name,
color: color,
icon: icon,
isIncome: false, // по умолчанию false
userId: 'default_user',
// userId будет установлен в CategoryCubit
);
context.read<CategoryCubit>().addCategory(newCategory);
},
),
),
);
},
child: const Icon(Icons.add),
),
);
}
}
+2
View File
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import '../../theme/custom_colors.dart';
import '/l10n/app_localizations.dart';
import '../../logic/auth/auth_bloc.dart';
@@ -101,6 +102,7 @@ class _HomePageState extends State<HomePage> {
],
currentIndex: _selectedIndex,
selectedItemColor: Theme.of(context).colorScheme.primary,
unselectedItemColor: Theme.of(context).extension<CustomColors>()?.unselectedIcon,
onTap: _onItemTapped,
),
);
@@ -38,7 +38,7 @@ class _AddTransactionDialogState extends State<AddTransactionDialog> {
void initState() {
super.initState();
// Комментарий: Устанавливаем начальное значение с датой и временем.
_dateController.text = DateFormat.yMd().add_Hm().format(_selectedDateTime);
_dateController.text = DateFormat('dd-MM-yyyy').add_Hm().format(_selectedDateTime);
}
@override
@@ -78,7 +78,7 @@ class _AddTransactionDialogState extends State<AddTransactionDialog> {
pickedTime.minute,
);
// Комментарий: Обновляем текстовое поле с отформатированной датой и временем.
_dateController.text = DateFormat.yMd().add_Hm().format(_selectedDateTime);
_dateController.text = DateFormat('dd-MM-yyyy').add_Hm().format(_selectedDateTime);
});
}
+15
View File
@@ -1,3 +1,4 @@
import 'package:budget_app/pages/category/category_list_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '/l10n/app_localizations.dart';
@@ -97,6 +98,20 @@ class SettingsPage extends StatelessWidget {
),
),
const Divider(),
// Комментарий: ListTile для перехода на страницу редактирования категорий.
ListTile(
title: Text(localizations.editCategories),
subtitle: Text(localizations.editCategoriesDescription),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const CategoryListPage(),
),
);
},
),
const Divider(),
],
),
);
+2
View File
@@ -50,6 +50,7 @@ class AppTheme {
expense: Colors.grey[600]!, // Серый для расходов
divider: Colors.grey[300]!, // Светло-серый для разделителей
accent: Colors.black, // Черный для акцентов
unselectedIcon: Colors.grey[500]!, // Серый для невыбранных иконок
),
],
);
@@ -103,6 +104,7 @@ class AppTheme {
expense: Colors.grey[500]!, // Серый для расходов
divider: Colors.grey[700]!, // Темно-серый для разделителей
accent: Colors.white, // Белый для акцентов
unselectedIcon: Colors.grey[400]!, // Светло-серый для невыбранных иконок
),
],
);
+5
View File
@@ -9,12 +9,14 @@ class CustomColors extends ThemeExtension<CustomColors> {
required this.expense,
this.divider, // Добавлен цвет для разделителей
this.accent, // Добавлен цвет для акцентов
this.unselectedIcon, // Цвет для невыбранных иконок
});
final Color? income;
final Color? expense;
final Color? divider;
final Color? accent;
final Color? unselectedIcon; // Цвет для невыбранных иконок
@override
CustomColors copyWith({
@@ -22,12 +24,14 @@ class CustomColors extends ThemeExtension<CustomColors> {
Color? expense,
Color? divider,
Color? accent,
Color? unselectedIcon,
}) {
return CustomColors(
income: income ?? this.income,
expense: expense ?? this.expense,
divider: divider ?? this.divider,
accent: accent ?? this.accent,
unselectedIcon: unselectedIcon ?? this.unselectedIcon,
);
}
@@ -41,6 +45,7 @@ class CustomColors extends ThemeExtension<CustomColors> {
expense: Color.lerp(expense, other.expense, t),
divider: Color.lerp(divider, other.divider, t),
accent: Color.lerp(accent, other.accent, t),
unselectedIcon: Color.lerp(unselectedIcon, other.unselectedIcon, t),
);
}
}
+240
View File
@@ -33,6 +33,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.4.1"
archive:
dependency: transitive
description:
name: archive
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
url: "https://pub.dev"
source: hosted
version: "3.6.1"
args:
dependency: transitive
description:
@@ -145,6 +153,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.4"
chunked_stream:
dependency: transitive
description:
name: chunked_stream
sha256: b2fde5f81d780f0c1699b8347cae2e413412ae947fc6e64727cc48c6bb54c95c
url: "https://pub.dev"
source: hosted
version: "1.4.2"
circular_buffer:
dependency: transitive
description:
name: circular_buffer
sha256: b3a315fef3fee7fe58879643fc8ce21c7c2449d01c1a8a396dc9e24687f335c4
url: "https://pub.dev"
source: hosted
version: "0.12.0"
clock:
dependency: transitive
description:
@@ -185,6 +209,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.6"
csv:
dependency: transitive
description:
name: csv
sha256: c6aa2679b2a18cb57652920f674488d89712efaf4d3fdf2e537215b35fc19d6c
url: "https://pub.dev"
source: hosted
version: "6.0.0"
cupertino_icons:
dependency: "direct main"
description:
@@ -193,6 +225,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.8"
dart_console:
dependency: transitive
description:
name: dart_console
sha256: "03c23e1f9cc3ac02b608f834808003e6510a5b292a0449f43dfac1c78bd8ee85"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
dart_style:
dependency: transitive
description:
@@ -201,6 +241,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.0"
dcli:
dependency: transitive
description:
name: dcli
sha256: "881e88bbad0ada4e3a085a0b55e05afa8e4199392c0c45ac18e3dedc37305b9b"
url: "https://pub.dev"
source: hosted
version: "6.1.2"
dcli_common:
dependency: transitive
description:
name: dcli_common
sha256: f8f77bea6a6d7e4ec2dc24cb4f274fc582938057c2cba44ed0650195ecfcd3ad
url: "https://pub.dev"
source: hosted
version: "6.1.2"
dcli_core:
dependency: transitive
description:
name: dcli_core
sha256: "29fb4833aa950900936646190b30315db511a853273b9fe31d360e5f72c7560b"
url: "https://pub.dev"
source: hosted
version: "6.1.2"
dcli_terminal:
dependency: transitive
description:
name: dcli_terminal
sha256: fb50860855c6b2841aed5bcfb315fa83d1401e109691b6585773a24c149dc4b0
url: "https://pub.dev"
source: hosted
version: "6.1.2"
equatable:
dependency: "direct main"
description:
@@ -254,6 +326,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "9.1.1"
flutter_colorpicker:
dependency: "direct main"
description:
name: flutter_colorpicker
sha256: "969de5f6f9e2a570ac660fb7b501551451ea2a1ab9e2097e89475f60e07816ea"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
flutter_iconpicker:
dependency: "direct main"
description:
name: flutter_iconpicker
sha256: d53b35bcb73325fcfdd36931769a8e7ff33b38e3b7c39b518a226fd0a5f3dc29
url: "https://pub.dev"
source: hosted
version: "4.0.1"
flutter_lints:
dependency: "direct dev"
description:
@@ -272,6 +360,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
font_awesome_flutter:
dependency: transitive
description:
name: font_awesome_flutter
sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a
url: "https://pub.dev"
source: hosted
version: "10.8.0"
frontend_server_client:
dependency: transitive
description:
@@ -280,6 +376,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.0"
functional_data:
dependency: transitive
description:
name: functional_data
sha256: "76d17dc707c40e552014f5a49c0afcc3f1e3f05e800cd6b7872940bfe41a5039"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
get_it:
dependency: "direct main"
description:
@@ -296,6 +400,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.3"
globbing:
dependency: transitive
description:
name: globbing
sha256: "4f89cfaf6fa74c9c1740a96259da06bd45411ede56744e28017cc534a12b6e2d"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
graphs:
dependency: transitive
description:
@@ -352,6 +464,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.1.2"
ini:
dependency: transitive
description:
name: ini
sha256: "12a76c53591ffdf86d1265be3f986888a6dfeb34a85957774bc65912d989a173"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
intl:
dependency: "direct main"
description:
@@ -384,6 +504,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.2"
json2yaml:
dependency: transitive
description:
name: json2yaml
sha256: da94630fbc56079426fdd167ae58373286f603371075b69bf46d848d63ba3e51
url: "https://pub.dev"
source: hosted
version: "3.0.1"
json_annotation:
dependency: transitive
description:
@@ -424,6 +552,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.1.1"
lists:
dependency: transitive
description:
name: lists
sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
logger:
dependency: "direct main"
description:
@@ -472,6 +608,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
native_synchronization_temp:
dependency: transitive
description:
name: native_synchronization_temp
sha256: f9ad36a5054c606db10e3dc0c9c352e6d0d56d08621af5c470abf9fa41da40fa
url: "https://pub.dev"
source: hosted
version: "0.7.1"
nested:
dependency: transitive
description:
@@ -568,6 +712,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
posix:
dependency: transitive
description:
name: posix
sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61"
url: "https://pub.dev"
source: hosted
version: "6.0.3"
provider:
dependency: transitive
description:
@@ -584,6 +736,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.0"
pubspec_lock:
dependency: transitive
description:
name: pubspec_lock
sha256: ed5fc1ecd0cdc0e14475a091afcb2c4cbb00e74cebff17635e9abbec18d76cc4
url: "https://pub.dev"
source: hosted
version: "3.0.2"
pubspec_manager:
dependency: transitive
description:
name: pubspec_manager
sha256: "4000db36057ddc9c95f1c56fd209ce54b1e7c621280f52e159a83342b1e33d62"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
pubspec_parse:
dependency: transitive
description:
@@ -592,6 +760,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.0"
scope:
dependency: transitive
description:
name: scope
sha256: "0b056e5b64ca16a2db9e1eb35cf7fd05a9e99a6b15140f82bfa651d081e4819b"
url: "https://pub.dev"
source: hosted
version: "5.1.0"
scrollview_observer:
dependency: transitive
description:
name: scrollview_observer
sha256: "174d4efe7b79459a07662175c4db42c9862dcf78d3978e6e9c2d6c0d8137f4ca"
url: "https://pub.dev"
source: hosted
version: "1.26.1"
settings_yaml:
dependency: transitive
description:
name: settings_yaml
sha256: "31c389f57d21518866ff36ec08cb15bf5c28aa6d324c09ba34a5547474f2b603"
url: "https://pub.dev"
source: hosted
version: "8.3.0"
shelf:
dependency: transitive
description:
@@ -677,6 +869,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
strings:
dependency: transitive
description:
name: strings
sha256: "052836499f03897d3860a603b330c1ea3c8a14177b21f34b15a1295f36024aae"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
sum_types:
dependency: transitive
description:
name: sum_types
sha256: c0a0fad9a518d011987e1d9f27fc336194294e55dafdc3699363e52aa5776e09
url: "https://pub.dev"
source: hosted
version: "0.3.5"
system_info2:
dependency: transitive
description:
name: system_info2
sha256: "65206bbef475217008b5827374767550a5420ce70a04d2d7e94d1d2253f3efc9"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
term_glyph:
dependency: transitive
description:
@@ -709,6 +925,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
unicode:
dependency: transitive
description:
name: unicode
sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1"
url: "https://pub.dev"
source: hosted
version: "0.3.1"
uuid:
dependency: "direct main"
description:
@@ -717,6 +941,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.5.1"
validators2:
dependency: transitive
description:
name: validators2
sha256: "5c63054b2f47b6a3f39e0d0e3f5d38829db4545250144a34c9e1585466de4814"
url: "https://pub.dev"
source: hosted
version: "5.0.0"
vector_math:
dependency: transitive
description:
@@ -765,6 +997,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.3"
win32:
dependency: transitive
description:
name: win32
sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03"
url: "https://pub.dev"
source: hosted
version: "5.14.0"
xdg_directories:
dependency: transitive
description:
+2
View File
@@ -48,6 +48,8 @@ dependencies:
sdk: flutter
intl: ^0.20.2
bloc:
flutter_colorpicker: ^1.1.0
flutter_iconpicker: ^4.0.1
dev_dependencies: