import 'dart:io'; import 'package:auto_route/auto_route.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:remever/common/functions.dart'; import 'package:remever/common/resources.dart'; import 'package:remever/common/utils.dart'; import 'package:remever/common/widgets/typography.dart'; import 'package:remever/common/widgets/w_if.dart'; import 'package:remever/common/widgets/wspace.dart'; import 'package:remever/components/extensions/context.dart'; import 'package:remever/components/extensions/state.dart'; import 'package:remever/database/database.dart'; import 'package:remever/gen/assets.gen.dart'; import 'package:remever/inject.dart'; import 'package:remever/models/create_ticket_dto.dart'; import 'package:remever/router.gr.dart'; import 'package:remever/screens/collections/widgets/collection_progress_bar.dart'; import 'package:remever/screens/create_card/widgets/crud_ticket.dart'; import 'package:remever/services/tickets/tickets_interface.dart'; import 'package:remever/widgets/debug/app_debug.dart'; import 'package:remever/widgets/primary_button.dart'; import 'package:path/path.dart' as path; @RoutePage() class CreateScreen extends StatefulWidget { const CreateScreen({super.key, this.collection}); final Collection? collection; @override State createState() => _CreateScreenState(); } class _CreateScreenState extends State { CreateTicketDto _dto = CreateTicketDto(); // Constants for spacing and dimensions static const double _horizontalPadding = 16; static const double _verticalSpacing = 16; Future _pickImage(bool isQuestion) async { final result = await FilePicker.platform.pickFiles(); if (result == null || result.files.isEmpty) { showErrorToast('Файл не выбран'); return; } final filePath = result.files.single.path; if (filePath == null) { showErrorToast('Не удалось получить путь к файлу'); return; } // Получаем директорию документов final Directory directory = await getApplicationDocumentsDirectory(); final String ticketsDirPath = path.join(directory.path, 'tickets'); final Directory ticketsDir = Directory(ticketsDirPath); // Создаём директорию рекурсивно if (!(await ticketsDir.exists())) { await ticketsDir.create(recursive: true); } final String fileName = path.basename(filePath); final String destinationPath = path.join(ticketsDirPath, fileName); final copiedFile = await File(filePath).copy(destinationPath); safeSetState(() { _dto = isQuestion ? _dto.copyWith(questionImage: copiedFile.path) : _dto.copyWith(answerImage: copiedFile.path); }); } void _onCollectionTap() { context.pushRoute( CollectionSearchRoute( onCollectionSelect: (collection) { safeSetState(() => _dto = _dto.copyWith(collection: collection)); }, ), ); } Future _onCreateTap() async { if (_dto.collection == null || _dto.answer == null || _dto.question == null) { showErrorToast('Необходимо заполнить все поля'); return; } await getIt().createTicket(_dto); safeSetState(() => _dto = CreateTicketDto()); final tabsRouter = context.tabsRouter; tabsRouter.setActiveIndex(3); } void _openFullScreenField({ required String title, required String? content, required void Function(String?) onEditingComplete, }) { context.pushRoute( CrudCollectionFullscreenField( title: title, hint: '', height: 313, content: content, onEditingComplete: onEditingComplete, ), ); } void _updateDto(String value, bool isQuestion) { safeSetState(() { _dto = isQuestion ? _dto.copyWith(question: value) : _dto.copyWith(answer: value); }); } @override void initState() { super.initState(); _setInitialData(); } /// /// Простановка данных для редиректа из коллекции /// void _setInitialData() { if (widget.collection != null) { safeSetState(() => _dto = _dto.copyWith(collection: widget.collection)); } } PreferredSizeWidget _buildAppBar() { return AppBar( toolbarHeight: 66.h, backgroundColor: AppColors.white, shadowColor: Colors.transparent, title: AppTypography( 'Создать карточку', type: SemiBold20px(), color: AppColors.body_text, ), centerTitle: true, ); } Widget _buildMain(BuildContext context) { return Padding( padding: EdgeInsets.symmetric(horizontal: _horizontalPadding).r, child: Column( children: [ Expanded( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const HSpace(_verticalSpacing), _filters(), const HSpace(_verticalSpacing), _buildSection('Коллекция', _buildCollection(context)), const HSpace(_verticalSpacing), _buildSection( 'Вопрос', CrudTicket( onTextTap: () => _openFullScreenField( title: 'Вопрос', content: _dto.question, onEditingComplete: (res) => _updateDto(res!, true), ), onImageTap: () => _pickImage(true), isQuestion: true, dto: _dto, ), ), const HSpace(_verticalSpacing), _buildSection( 'Ответ', CrudTicket( onTextTap: () => _openFullScreenField( title: 'Ответ', content: _dto.answer, onEditingComplete: (res) => _updateDto(res!, false), ), onImageTap: () => _pickImage(false), isQuestion: false, dto: _dto, ), ), revertCard(), ], ), ), ), _buildCreateButton(), const HSpace(31), ], ), ); } Widget _buildSection(String title, Widget child) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AppTypography(title, type: Medium16px()), const HSpace(4), child, ], ); } Widget _buildCollection(BuildContext context) { return GestureDetector( onTap: _onCollectionTap, child: Container( constraints: BoxConstraints(minHeight: 66.h, maxHeight: 84.h), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12).r, color: AppColors.white, ), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8).r, child: Wif( condition: _dto.collection != null, builder: (context) => Row( children: [_buildAvatar(), const WSpace(5), _buildInfo()], ), fallback: (context) => Row( mainAxisAlignment: MainAxisAlignment.center, children: [ AppTypography('Выберите коллекцию', type: Bold14px()), ], ), ), ), ); } Widget _buildInfo() { return SizedBox( width: 230.w, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ _buildTitle(), const HSpace(4), Row( children: [ Assets.icons.typeCards.image( height: 18.h, width: 18.w, color: AppColors.disabled, ), const WSpace(2), AppTypography( '${_dto.collection!.likesCount.toString()} ${Utils.declOfNum(_dto.collection!.likesCount, ['карточек', 'карточки', 'карточек'])}', type: Regular14px(), color: AppColors.disabled, ), ], ), const HSpace(6), const CollectionProgressBar(), ], ), ); } Widget _buildTitle() { return AppTypography( _dto.collection!.title, type: Medium16px(), maxLines: 2, softWrap: true, ); } Widget _buildAvatar() { return SizedBox.square( dimension: 50.r, child: DecoratedBox( decoration: BoxDecoration(shape: BoxShape.circle, color: AppColors.bg), child: Wif( condition: _dto.collection?.image != null, builder: (context) => ClipOval( child: Image.file( File(_dto.collection!.image!), fit: BoxFit.cover, ), ), fallback: (context) => Center( child: AppTypography( _dto.collection!.title.substring(0, 1), type: Bold34px(), ), ), ), ), ); } Widget revertCard() { return SizedBox( height: 52.h, child: Row( children: [ Center( child: Assets.icons.typeFlip2.image(height: 20.h, width: 20.w), ), const WSpace(2), Flexible( fit: FlexFit.tight, child: AppTypography( 'Создать карточку-наоборот', type: Medium16px(), ), ), SizedBox( height: 20.h, width: 36.w, child: FittedBox( fit: BoxFit.contain, child: CupertinoSwitch( activeTrackColor: AppColors.primary, value: _dto.needRevert ?? false, onChanged: (value) => safeSetState( () => _dto = _dto.copyWith(needRevert: value), ), ), ), ), ], ), ); } Widget _buildCreateButton() { return PrimaryButton( color: AppColors.primary, onTap: _onCreateTap, child: AppTypography( 'Создать карточку', type: Medium14px(), color: AppColors.white, ), ); } Widget _filters() { return AppDebug( builder: (context, isDebug) { if (!isDebug) return const SizedBox(); return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ _buildFilterButton(AppColors.gray_bg, 'Запомнить', () {}), const WSpace(10), _buildFilterButton(AppColors.white, 'Держать в фокусе', () {}), ], ); }, ); } Widget _buildFilterButton(Color color, String title, VoidCallback onTap) { return GestureDetector( onTap: onTap, child: Container( width: 158.h, height: 36.h, decoration: BoxDecoration( borderRadius: BorderRadius.circular(16).r, color: color, ), child: Center(child: AppTypography(title, type: SemiBold14px())), ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.gray_bg, appBar: _buildAppBar(), body: _buildMain(context), ); } }