diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index bae12ea..795944b 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqlite3_flutter_libs","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"flutter_displaymode","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_displaymode-0.6.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.27/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/path_provider_android-2.2.16/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqlite3_flutter_libs","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_macos","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-3.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqlite3_flutter_libs","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_linux","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.2.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":false,"dependencies":["url_launcher_linux"],"dev_dependency":false},{"name":"sqlite3_flutter_libs","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_linux","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_windows","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":["url_launcher_windows"],"dev_dependency":false},{"name":"sqlite3_flutter_libs","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_windows","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_web","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1/","dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","dependencies":["url_launcher_web"],"dev_dependency":false},{"name":"url_launcher_web","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/url_launcher_web-2.4.0/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_displaymode","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":["path_provider"]},{"name":"fluttertoast","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["url_launcher_web","url_launcher_windows","url_launcher_linux"]},{"name":"sqlite3_flutter_libs","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2025-09-08 15:45:24.059280","version":"3.29.0","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqlite3_flutter_libs","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"flutter_displaymode","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_displaymode-0.6.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.27/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/path_provider_android-2.2.16/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqlite3_flutter_libs","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_macos","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-3.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqlite3_flutter_libs","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_linux","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.2.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":false,"dependencies":["url_launcher_linux"],"dev_dependency":false},{"name":"sqlite3_flutter_libs","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_linux","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_windows","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","native_build":true,"dependencies":["url_launcher_windows"],"dev_dependency":false},{"name":"sqlite3_flutter_libs","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/sqlite3_flutter_libs-0.5.32/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_windows","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"file_picker","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/file_picker-10.0.0/","dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_web","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1/","dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/package_info_plus-8.3.0/","dependencies":[],"dev_dependency":false},{"name":"share_plus","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/share_plus-10.1.4/","dependencies":["url_launcher_web"],"dev_dependency":false},{"name":"url_launcher_web","path":"/Users/vitalijnecitajlo/.pub-cache/hosted/pub.dev/url_launcher_web-2.4.0/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_displaymode","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":["path_provider"]},{"name":"fluttertoast","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share_plus","dependencies":["url_launcher_web","url_launcher_windows","url_launcher_linux"]},{"name":"sqlite3_flutter_libs","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2025-09-08 17:40:02.091441","version":"3.29.0","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/lib/screens/crud_collection/crud_collection.dart b/lib/screens/crud_collection/crud_collection.dart index 447b5ab..e10687e 100644 --- a/lib/screens/crud_collection/crud_collection.dart +++ b/lib/screens/crud_collection/crud_collection.dart @@ -1,5 +1,5 @@ -import 'dart:convert'; import 'dart:io'; +import 'dart:typed_data'; import 'package:auto_route/auto_route.dart'; import 'package:file_picker/file_picker.dart'; @@ -36,88 +36,85 @@ class CrudCollectionScreen extends StatefulWidget { } class _CrudCollectionScreenState extends State { - /// Флаг публичности коллекции + late CrudCollectionDto _collection; bool _isPublic = false; - CrudCollectionDto? _collection; - - /// Смена публичности - void _setPublic(bool public) { - _collection = _collection?.copyWith(isPublic: public); - safeSetState(() => _isPublic = public); - } - @override void initState() { + super.initState(); + _initializeCollection(); + } + + void _initializeCollection() { _collection = CrudCollectionDto( desc: widget.editedCollection?.desc ?? '', title: widget.editedCollection?.title ?? '', isPublic: widget.editedCollection?.isPublic ?? false, avatar: widget.editedCollection?.image, ); - - super.initState(); + _isPublic = _collection.isPublic; } - void _pickImage() async { + Future _pickImage() async { final result = await FilePicker.platform.pickFiles(); - if (result == null || result.files.isEmpty) { + if (result?.files.single.path case final String? path?) { + try { + final bytes = await File(path!).readAsBytes(); + _updateCollection(avatar: bytes); + } catch (e) { + showErrorToast('Не удалось загрузить изображение'); + } + } else { showErrorToast('Файл не выбран'); - return; } + } - final filePath = result.files.single.path; - - if (filePath == null) { - showErrorToast('Не удалось получить путь к файлу'); - - return; - } - - final file = File(filePath); - final bytes = await file.readAsBytes(); - - // final base64String = base64Encode(bytes); - - _collection = _collection?.copyWith(avatar: bytes); - + void _updateCollection({ + String? title, + String? desc, + bool? isPublic, + Uint8List? avatar, + }) { + _collection = _collection.copyWith( + title: title ?? _collection.title, + desc: desc ?? _collection.desc, + isPublic: isPublic ?? _collection.isPublic, + avatar: avatar ?? _collection.avatar, + ); safeSetState(() {}); } @override Widget build(BuildContext context) { - logger.logBuild('build create screen'); - return Scaffold( backgroundColor: AppColors.gray_bg, - appBar: _buildAppBar(context), - body: _buildMainBody(context), + appBar: _buildAppBar(), + body: _buildMainBody(), ); } - /// Основное тело экрана - Widget _buildMainBody(BuildContext context) { + Widget _buildMainBody() { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16).r, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ const HSpace(16), - _buildPhotoAndTitle(context), + _buildPhotoAndTitle(), const HSpace(16), - ..._buildDescription(context), + ..._buildDescription(), const HSpace(16), - // _buildPublickSwitch(), + // _buildPublicSwitch(), const HSpace(16), AnimatedOpacity( // opacity: _isPublic ? 1 : 0, opacity: 0, - duration: const Duration(seconds: 1), + duration: const Duration(milliseconds: 300), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ ..._buildTagButton(), const HSpace(16), _buildTagsList(), @@ -125,7 +122,7 @@ class _CrudCollectionScreenState extends State { ], ), ), - _buildCreateBtn(context), + _buildCreateBtn(), const BottomSafeSpace(), ], ), @@ -133,30 +130,10 @@ class _CrudCollectionScreenState extends State { ); } - ///Кнопка создания - Widget _buildCreateBtn(BuildContext context) { + Widget _buildCreateBtn() { return PrimaryButton( height: 52, - onTap: () async { - if (_collection!.desc.isEmpty && _collection!.title.isEmpty) { - showErrorToast( - 'Для создания публичной коллекции добавьте описание и тэги', - ); - - return; - } - - widget.editedCollection != null - ? await getIt().updateCollection( - _collection!, - widget.editedCollection!.id, - ) - : await getIt().createCollection( - _collection!, - ); - - context.back(); - }, + onTap: _handleCreateOrUpdate, color: AppColors.primary, child: AppTypography( widget.editedCollection == null @@ -168,94 +145,124 @@ class _CrudCollectionScreenState extends State { ); } - /// Построение списка тегов + Future _handleCreateOrUpdate() async { + if (!_isCollectionValid()) return; + + if (!_hasChanges()) { + context.back(); + } + + try { + final collectionService = getIt(); + + widget.editedCollection != null + ? await collectionService.updateCollection( + _collection, + widget.editedCollection!.id, + ) + : await collectionService.createCollection(_collection); + + context.back(); + } catch (e) { + showErrorToast( + 'Ошибка при ${widget.editedCollection != null ? 'обновлении' : 'создании'} коллекции', + ); + } + } + + bool _isCollectionValid() { + if (_collection.title.isEmpty && _collection.desc.isEmpty) { + showErrorToast('Для создания коллекции добавьте название и описание'); + return false; + } + + if (_isPublic && _collection.desc.isEmpty) { + showErrorToast( + 'Для создания публичной коллекции добавьте описание и тэги', + ); + return false; + } + + return true; + } + Widget _buildTagsList() { return SizedBox( height: 68.h, child: Row( - children: [ + children: [ Expanded( child: Wrap( runSpacing: 8.r, spacing: 8.r, - children: List.generate(6, (int index) { - return GestureDetector( - onTap: () {}, - child: Container( - height: 30, - decoration: BoxDecoration( - borderRadius: - const BorderRadius.all(Radius.circular(6)).r, - color: const Color(0xFFFFE4E6), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - AppTypography( - 'tag $index', - type: Regular14px(), - height: 0.95, - color: AppColors.danger, - ), - const WSpace(8), - Center( - child: Icon( - Icons.close, - size: 14.r, - color: AppColors.danger, - ), - ), - ], - ), - ), - ), - ); - }), + children: List.generate(6, _buildTagItem), ), ), const WSpace(9), - GestureDetector( - onTap: () { - showCuperModalBottomSheet( - context: context, - height: 270.h, - builder: (BuildContext context) => const TagsDialog(), - ); - }, - child: AppTypography( - '+13', - type: Medium16px(), - color: AppColors.primary, - ), - ), + _buildAddTagButton(), ], ), ); } - /// Построение кнопки добавления тега + Widget _buildTagItem(int index) { + return GestureDetector( + onTap: () {}, + child: Container( + height: 30, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(6)).r, + color: const Color(0xFFFFE4E6), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + AppTypography( + 'tag $index', + type: Regular14px(), + height: 0.95, + color: AppColors.danger, + ), + const WSpace(8), + Icon(Icons.close, size: 14.r, color: AppColors.danger), + ], + ), + ), + ), + ); + } + + Widget _buildAddTagButton() { + return GestureDetector( + onTap: _showTagsDialog, + child: AppTypography('+13', type: Medium16px(), color: AppColors.primary), + ); + } + + void _showTagsDialog() { + showCuperModalBottomSheet( + context: context, + height: 270.h, + builder: (_) => const TagsDialog(), + ); + } + List _buildTagButton() { - return [ + return [ AppTypography('Тэги', type: SemiBold14px()), const HSpace(4), - CrudCollectionField( - height: 42, - width: 348, - hint: 'Добавить тэг', - // onTap: () => context.pushRoute(const AddTagsRoute()), - ), + CrudCollectionField(height: 42, width: 348, hint: 'Добавить тэг'), ]; } - /// Построение свитчера на публичность коллекции - Widget _buildPublickSwitch() { + Widget _buildPublicSwitch() { return GestureDetector( - onTap: () => _setPublic(!_isPublic), + onTap: _togglePublic, child: Row( - children: [ + children: [ SizedBox.square( dimension: 20.r, child: Assets.icons.typePublic.image(color: AppColors.primary), @@ -287,135 +294,134 @@ class _CrudCollectionScreenState extends State { ); } - /// Построение блока с описанием - List _buildDescription(BuildContext context) { - return [ + void _togglePublic() => _setPublic(!_isPublic); + + void _setPublic(bool isPublic) { + _updateCollection(isPublic: isPublic); + safeSetState(() => _isPublic = isPublic); + } + + List _buildDescription() { + return [ AppTypography('Описание', type: SemiBold14px()), const HSpace(4), CrudCollectionField( height: 110, width: 348, hint: 'Добавить описание', - content: _collection?.desc, - onTap: () { - context.pushRoute( - CrudCollectionFullscreenField( + content: _collection.desc, + onTap: + () => _navigateToFullscreenField( title: 'Описание', height: 333, - content: _collection?.desc, - onEditingComplete: (res) { - safeSetState( - () => _collection = _collection?.copyWith(desc: res ?? ''), - ); - }, + content: _collection.desc, + onResult: (result) => _updateCollection(desc: result ?? ''), ), - ); - }, ), ]; } - /// Построение блока фото и заголовка - Widget _buildPhotoAndTitle(BuildContext context) { - return Row( - children: [_buildPhoto(), const WSpace(8), _buildTitle(context)], - ); - } - - /// Построение поля для ввода заголовка - Widget _buildTitle(BuildContext context) { + Widget _buildTitle() { return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ AppTypography('Название', type: SemiBold14px()), const HSpace(4), CrudCollectionField( height: 91, width: 225, hint: 'Добавить название', - content: _collection?.title, - onTap: () { - context.pushRoute( - CrudCollectionFullscreenField( + content: _collection.title, + onTap: + () => _navigateToFullscreenField( title: 'Название', hint: 'Максимальное количество символов - 250', - content: _collection?.title, - onEditingComplete: (res) { - safeSetState( - () => _collection = _collection?.copyWith(title: res ?? ''), - ); - }, + content: _collection.title, + onResult: (result) => _updateCollection(title: result ?? ''), ), - ); - }, ), ], ); } - /// Построение обложки + void _navigateToFullscreenField({ + required String title, + String? hint, + String? content, + required Function(String?) onResult, + double height = 91, + }) { + context.pushRoute( + CrudCollectionFullscreenField( + title: title, + hint: hint, + height: height, + content: content, + onEditingComplete: onResult, + ), + ); + } + + Widget _buildPhotoAndTitle() { + return Row( + children: [ + _buildPhoto(), + const WSpace(8), + Expanded(child: _buildTitle()), + ], + ); + } + Widget _buildPhoto() { return GestureDetector( - onTap: () => _pickImage(), + onTap: _pickImage, child: SizedBox.square( dimension: 115.r, child: DecoratedBox( decoration: const BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( - colors: [Color(0xFFB6AAFE), Color(0xFFDBD7F4)], + colors: [Color(0xFFB6AAFE), Color(0xFFDBD7F4)], begin: Alignment.bottomLeft, end: Alignment.topRight, ), ), child: Wif( - condition: _collection!.avatar != null, + condition: _collection.avatar != null, builder: - (context) => ClipOval( - child: Image.memory(_collection!.avatar!, fit: BoxFit.cover), - ), - fallback: - (context) => SizedBox.square( - dimension: 32.r, - child: Center( - child: Assets.icons.typePhoto.image( - height: 32.h, - width: 32.w, - color: AppColors.primary, - ), + (_) => ClipOval( + child: Image.memory( + _collection.avatar!, + fit: BoxFit.cover, + errorBuilder: (_, __, ___) => _buildPhotoPlaceholder(), ), ), + fallback: (_) => _buildPhotoPlaceholder(), ), ), ), ); } - /// Построение шапки - AppBar _buildAppBar(BuildContext context) { + Widget _buildPhotoPlaceholder() { + return SizedBox.square( + dimension: 32.r, + child: Center( + child: Assets.icons.typePhoto.image( + height: 32.h, + width: 32.w, + color: AppColors.primary, + ), + ), + ); + } + + AppBar _buildAppBar() { return AppBar( toolbarHeight: 56.h, backgroundColor: AppColors.white, shadowColor: Colors.transparent, leading: IconButton( - onPressed: () async { - if (widget.editedCollection != null) { - final bool? res = await showCuperModalBottomSheet( - context: context, - height: 262.h, - builder: - (BuildContext context) => const AlertInfoDialog( - title: 'Вы хотите сбросить все внесенные изменения?', - acceptTitle: 'Да, сбросить', - declineTitle: 'Нет, оставить', - ), - ); - - if (res != null && res) context.back(); - } else { - context.back(); - } - }, + onPressed: _handleBackPress, icon: const Icon(CupertinoIcons.left_chevron, color: Colors.black), ), centerTitle: true, @@ -429,35 +435,66 @@ class _CrudCollectionScreenState extends State { color: AppColors.body_text, ), ), - actions: [ - Wif( - condition: widget.editedCollection != null, - builder: (BuildContext context) { - return Padding( - padding: const EdgeInsets.only(right: 16).r, - child: GestureDetector( - onTap: () { - showCuperModalBottomSheet( - context: context, - height: 262.h, - builder: - (BuildContext context) => const AlertInfoDialog( - title: 'Вы хотите сбросить все внесенные изменения?', - acceptTitle: 'Да, сбросить', - declineTitle: 'Нет, оставить', - ), - ); - }, - child: Assets.icons.typeTrash.image( - height: 24.h, - width: 24.w, - color: AppColors.primary, - ), + actions: [ + if (widget.editedCollection != null && _hasChanges()) + Padding( + padding: const EdgeInsets.only(right: 16).r, + child: GestureDetector( + onTap: _showResetDialog, + child: Assets.icons.typeTrash.image( + height: 24.h, + width: 24.w, + color: AppColors.danger, ), - ); - }, - ), + ), + ), ], ); } + + Future _handleBackPress() async { + if (widget.editedCollection != null) { + final shouldExit = await _showExitDialog(); + if (shouldExit == true) context.back(); + } else { + context.back(); + } + } + + Future _showExitDialog() async { + // Показываем диалог только если есть редактируемая коллекция и есть изменения + if (widget.editedCollection != null && _hasChanges()) { + return showCuperModalBottomSheet( + context: context, + height: 262.h, + builder: + (_) => const AlertInfoDialog( + title: 'Вы хотите сбросить все внесенные изменения?', + acceptTitle: 'Да, сбросить', + declineTitle: 'Нет, оставить', + ), + ); + } + return true; + } + + bool _hasChanges() { + // Если нет редактируемой коллекции, значит это создание новой + if (widget.editedCollection == null) return false; + + // Сравниваем все поля + return _collection.title != widget.editedCollection!.title || + _collection.desc != widget.editedCollection!.desc || + _collection.isPublic != widget.editedCollection!.isPublic || + _collection.avatar != widget.editedCollection!.image; + } + + void _showResetDialog() { + _showExitDialog().then((result) { + if (result == true) { + _initializeCollection(); + safeSetState(() {}); + } + }); + } } diff --git a/lib/screens/crud_collection/widgets/crud_collection_fullscreen_field.dart b/lib/screens/crud_collection/widgets/crud_collection_fullscreen_field.dart index e532156..c8abf45 100644 --- a/lib/screens/crud_collection/widgets/crud_collection_fullscreen_field.dart +++ b/lib/screens/crud_collection/widgets/crud_collection_fullscreen_field.dart @@ -39,10 +39,10 @@ class _CrudCollectionFullscreenFieldState @override void initState() { + super.initState(); if (widget.content != null) { _controller.text = widget.content!; } - super.initState(); } @override @@ -58,15 +58,14 @@ class _CrudCollectionFullscreenFieldState top: false, child: Scaffold( backgroundColor: AppColors.gray_bg, - appBar: _buildAppBar(context), - body: _buildMainBody(context), + appBar: _buildAppBar(), + body: _buildMainBody(), ), ), ); } - /// Построение основного тела экрана - Widget _buildMainBody(BuildContext context) { + Widget _buildMainBody() { return Stack( children: [ Padding( @@ -77,7 +76,7 @@ class _CrudCollectionFullscreenFieldState crossAxisAlignment: CrossAxisAlignment.start, children: [ const HSpace(16), - _buildField(context), + _buildField(), if (widget.hint != null) ...[ const HSpace(16), AppTypography( @@ -96,12 +95,10 @@ class _CrudCollectionFullscreenFieldState ); } - /// Построение интерактивной плашки меню Widget _buildMenu() { return Consumer( - builder: (context, screenHeight, _) { + builder: (_, screenHeight, __) { return AnimatedOpacity( - // opacity: screenHeight.isOpen ? 1 : 0, opacity: 1, duration: const Duration(milliseconds: 500), child: Container( @@ -126,7 +123,6 @@ class _CrudCollectionFullscreenFieldState ); } - /// Кнопка "Вставить из буфера обмена" Widget _buildPasteButton() { return GestureDetector( onTap: _onPasteTap, @@ -134,22 +130,20 @@ class _CrudCollectionFullscreenFieldState ); } - /// Обработка нажатия на кнопку "Вставить" - void _onPasteTap() async { + Future _onPasteTap() async { try { - final ClipboardData? data = await Clipboard.getData('text/plain'); - if (data?.text == null || data!.text!.isEmpty) { + final data = await Clipboard.getData(Clipboard.kTextPlain); + if (data?.text?.isEmpty ?? true) { showErrorToast('Не удалось получить текст из буфера обмена'); return; } - _controller.text += ' ${data.text}'; + _controller.text += ' ${data!.text}'; showSuccessToast('Текст вставлен из буфера обмена'); } catch (e) { showErrorToast('Ошибка при вставке текста: $e'); } } - /// Кнопка "Скопировать в буфер обмена" Widget _buildCopyButton() { return GestureDetector( onTap: _onCopyTap, @@ -157,8 +151,7 @@ class _CrudCollectionFullscreenFieldState ); } - /// Обработка нажатия на кнопку "Копировать" - void _onCopyTap() async { + Future _onCopyTap() async { if (_controller.text.isEmpty) { showErrorToast('Нет содержимого для отправки в буфер обмена'); return; @@ -171,45 +164,30 @@ class _CrudCollectionFullscreenFieldState } } - /// Кнопка "Подтвердить" Widget _buildSubmitButton() { return GestureDetector( onTap: _onSubmitTap, child: SizedBox.square( dimension: 32.r, - child: DecoratedBox( - decoration: const BoxDecoration( + child: const DecoratedBox( + decoration: BoxDecoration( shape: BoxShape.circle, color: AppColors.primary, ), child: Center( - child: Assets.icons.typeCheck.image( - height: 24.h, - width: 24.w, - color: AppColors.white, - ), + child: Icon(Icons.check, color: AppColors.white, size: 24), ), ), ), ); } - /// Обработка нажатия на кнопку "Подтвердить" void _onSubmitTap() { - if (_controller.text.isEmpty) { - showErrorToast( - 'Для создания публичной коллекции добавьте описание и тэги', - ); - return; - } - widget.onEditingComplete(_controller.text); - context.back(); } - /// Построение поля ввода - Widget _buildField(BuildContext context) { + Widget _buildField() { return SizedBox( height: widget.height.h, child: DecoratedBox( @@ -236,30 +214,26 @@ class _CrudCollectionFullscreenFieldState ); } - /// Построение шапки - AppBar _buildAppBar(BuildContext context) { + AppBar _buildAppBar() { return AppBar( toolbarHeight: 56.h, backgroundColor: AppColors.white, shadowColor: Colors.transparent, leading: IconButton( - onPressed: () => _handleBackPress(context), + onPressed: () => _handleBackPress(), icon: const Icon(CupertinoIcons.left_chevron, color: Colors.black), ), centerTitle: true, - title: GestureDetector( - // onLongPress: () => _showExitDialog(context), - child: AppTypography( - widget.title, - type: SemiBold20px(), - color: AppColors.body_text, - ), + title: AppTypography( + widget.title, + type: SemiBold20px(), + color: AppColors.body_text, ), actions: [ Padding( padding: const EdgeInsets.only(right: 16).r, child: GestureDetector( - onTap: () => _showResetDialog(context), + onTap: _showResetDialog, child: Assets.icons.typeTrash.image( height: 24.h, width: 24.w, @@ -271,39 +245,46 @@ class _CrudCollectionFullscreenFieldState ); } - /// Обработка нажатия на кнопку "Назад" - void _handleBackPress(BuildContext context) async { - // final bool? shouldExit = await _showExitDialog(context); - // if (shouldExit ?? false) { - context.back(); - // } + Future _handleBackPress() async { + final shouldExit = await _showExitDialog(); + if (shouldExit ?? false) { + context.back(); + } } - /// Показать диалог выхода - Future _showExitDialog(BuildContext context) async { - return showCuperModalBottomSheet( + Future _showExitDialog() async { + final res = await showCuperModalBottomSheet( context: context, height: 262.h, builder: - (context) => const AlertInfoDialog( - title: 'Вы хотите выйти из режима создания описания коллекции?', - acceptTitle: 'Выйти, не сохранять', + (_) => const AlertInfoDialog( + title: 'У вас есть несохраненные изменения', + acceptTitle: 'Выйти', declineTitle: 'Сохранить и выйти', ), ); + + if (res == null) return false; + if (res) return true; + + widget.onEditingComplete(_controller.text); + return true; } - /// Показать диалог сброса - void _showResetDialog(BuildContext context) { - // showCuperModalBottomSheet( - // context: context, - // height: 262.h, - // builder: - // (context) => const AlertInfoDialog( - // title: 'Вы хотите сбросить все внесенные изменения?', - // acceptTitle: 'Да, сбросить', - // declineTitle: 'Нет, оставить', - // ), - // ); + Future _showResetDialog() async { + final res = await showCuperModalBottomSheet( + context: context, + height: 262.h, + builder: + (_) => AlertInfoDialog( + title: 'Удалить вcе содержимое поля "${widget.title}"?', + acceptTitle: 'Удалить', + declineTitle: 'Отменить', + ), + ); + + if (res == true) { + _controller.clear(); + } } }