Доработка создания карточки в коллекции

This commit is contained in:
2025-04-02 21:52:44 +03:00
parent 17dff72655
commit a3ef313e7c

View File

@@ -1,6 +1,4 @@
import 'dart:io'; import 'dart:io';
import 'dart:math';
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
@@ -34,35 +32,32 @@ class CreateScreen extends StatefulWidget {
class _CreateScreenState extends State<CreateScreen> { class _CreateScreenState extends State<CreateScreen> {
CreateTicketDto _dto = CreateTicketDto(); CreateTicketDto _dto = CreateTicketDto();
void _pickImage(bool isQuestion) async { // Constants for spacing and dimensions
final result = await FilePicker.platform.pickFiles(); static const double _horizontalPadding = 16;
static const double _verticalSpacing = 16;
Future<void> _pickImage(bool isQuestion) async {
final result = await FilePicker.platform.pickFiles();
if (result == null || result.files.isEmpty) { if (result == null || result.files.isEmpty) {
showErrorToast('Файл не выбран'); showErrorToast('Файл не выбран');
return; return;
} }
final filePath = result.files.single.path; final filePath = result.files.single.path;
if (filePath == null) { if (filePath == null) {
showErrorToast('Не удалось получить путь к файлу'); showErrorToast('Не удалось получить путь к файлу');
return; return;
} }
final file = File(filePath); final file = File(filePath);
final bytes = await file.readAsBytes(); final bytes = await file.readAsBytes();
safeSetState(() {
_dto = _dto =
isQuestion isQuestion
? _dto.copyWith(questionImage: bytes) ? _dto.copyWith(questionImage: bytes)
: _dto.copyWith(answerImage: bytes); : _dto.copyWith(answerImage: bytes);
});
safeSetState(() {});
} }
void _onCollectionTap() { void _onCollectionTap() {
{
context.pushRoute( context.pushRoute(
CollectionSearchRoute( CollectionSearchRoute(
onCollectionSelect: (collection) { onCollectionSelect: (collection) {
@@ -71,31 +66,48 @@ class _CreateScreenState extends State<CreateScreen> {
), ),
); );
} }
}
void _onCreateTap() async { Future<void> _onCreateTap() async {
if (_dto.collection == null || if (_dto.collection == null ||
_dto.answer == null || _dto.answer == null ||
_dto.question == null) { _dto.question == null) {
showErrorToast('Необходимо заполнить все поля'); showErrorToast('Необходимо заполнить все поля');
return; return;
} }
await getIt<TicketsInterface>().createTicket(_dto); await getIt<TicketsInterface>().createTicket(_dto);
context.pushRoute(CollectionRoute()); safeSetState(() => _dto = CreateTicketDto());
final tabsRouter = context.tabsRouter;
tabsRouter.setActiveIndex(3);
} }
@override void _openFullScreenField({
Widget build(BuildContext context) { required String title,
return Scaffold( required String? content,
backgroundColor: AppColors.gray_bg, required void Function(String?) onEditingComplete,
appBar: _buildAppBar(), }) {
body: _buildMain(context), context.pushRoute(
CrudCollectionFullscreenField(
title: title,
hint: '',
height: 313,
content: content,
onEditingComplete: onEditingComplete,
),
); );
} }
AppBar _buildAppBar() { void _updateDto(String value, bool isQuestion) {
safeSetState(() {
_dto =
isQuestion
? _dto.copyWith(question: value)
: _dto.copyWith(answer: value);
});
}
PreferredSizeWidget _buildAppBar() {
return AppBar( return AppBar(
toolbarHeight: 66.h, toolbarHeight: 66.h,
backgroundColor: AppColors.white, backgroundColor: AppColors.white,
@@ -111,66 +123,48 @@ class _CreateScreenState extends State<CreateScreen> {
Widget _buildMain(BuildContext context) { Widget _buildMain(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16).r, padding: EdgeInsets.symmetric(horizontal: _horizontalPadding).r,
child: Column( child: Column(
children: <Widget>[ children: [
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: [
const HSpace(16), const HSpace(_verticalSpacing),
_filters(), _filters(),
const HSpace(16), const HSpace(_verticalSpacing),
AppTypography('Коллекция', type: Medium16px()), _buildSection('Коллекция', _buildCollection(context)),
const HSpace(4), const HSpace(_verticalSpacing),
_buildCollection(context), _buildSection(
const HSpace(16), 'Вопрос',
AppTypography('Вопрос', type: Medium16px()),
const HSpace(4),
CrudTicket( CrudTicket(
onTextTap: () { onTextTap:
context.pushRoute( () => _openFullScreenField(
CrudCollectionFullscreenField(
title: 'Вопрос', title: 'Вопрос',
hint: '',
height: 313,
content: _dto.question, content: _dto.question,
onEditingComplete: (res) { onEditingComplete: (res) => _updateDto(res!, true),
safeSetState(() {
_dto = _dto.copyWith(question: res);
});
},
), ),
);
},
onImageTap: () => _pickImage(true), onImageTap: () => _pickImage(true),
isQuestion: true, isQuestion: true,
dto: _dto, dto: _dto,
), ),
const HSpace(16),
AppTypography('Ответ', type: Medium16px()),
const HSpace(4),
CrudTicket(
onTextTap: () {
context.pushRoute(
CrudCollectionFullscreenField(
title: 'Ответ',
hint: '',
height: 313,
content: _dto.answer,
onEditingComplete: (res) {
safeSetState(() {
_dto = _dto.copyWith(answer: res);
});
},
), ),
); const HSpace(_verticalSpacing),
}, _buildSection(
'Ответ',
CrudTicket(
onTextTap:
() => _openFullScreenField(
title: 'Ответ',
content: _dto.answer,
onEditingComplete: (res) => _updateDto(res!, false),
),
onImageTap: () => _pickImage(false), onImageTap: () => _pickImage(false),
isQuestion: false, isQuestion: false,
dto: _dto, dto: _dto,
), ),
),
revertCard(), revertCard(),
], ],
), ),
@@ -183,91 +177,20 @@ class _CreateScreenState extends State<CreateScreen> {
); );
} }
Widget revertCard() { Widget _buildSection(String title, Widget child) {
return SizedBox( return Column(
height: 52.h, crossAxisAlignment: CrossAxisAlignment.start,
child: Row( children: [
children: <Widget>[ AppTypography(title, type: Medium16px()),
Center( const HSpace(4),
child: Assets.icons.typeFlip2.image(height: 20.h, width: 20.w), child,
),
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: (bool value) {
safeSetState(() {
_dto = _dto.copyWith(needRevert: value);
});
},
),
),
),
], ],
),
);
}
Widget _filters() {
return AppDebug(
builder: (context, isDebug) {
if (!isDebug) return SizedBox();
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildFilterButton(AppColors.gray_bg, 'Запомнить', () {}),
_buildFilterButton(AppColors.white, 'Держать в фокусе', () {}),
],
);
},
);
}
Widget _buildCreateButton() {
return PrimaryButton(
color: AppColors.primary,
child: AppTypography(
'Создать карточку',
type: Medium14px(),
color: AppColors.white,
),
onTap: () => _onCreateTap(),
);
}
///
/// Построение кнопки фильтра
///
Widget _buildFilterButton(Color color, String title, void Function()? onTap) {
return GestureDetector(
onTap: onTap,
child: Container(
width: 158.h,
height: 36.h,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(16)).r,
color: color,
),
child: Center(child: AppTypography(title, type: SemiBold14px())),
),
); );
} }
Widget _buildCollection(BuildContext context) { Widget _buildCollection(BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () => _onCollectionTap(), onTap: _onCollectionTap,
child: Container( child: Container(
constraints: BoxConstraints(minHeight: 66.h, maxHeight: 84.h), constraints: BoxConstraints(minHeight: 66.h, maxHeight: 84.h),
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -277,38 +200,33 @@ class _CreateScreenState extends State<CreateScreen> {
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8).r, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8).r,
child: Wif( child: Wif(
condition: _dto.collection != null, condition: _dto.collection != null,
builder: (context) { builder:
return Row( (context) => Row(
children: <Widget>[_buildAvatar(), const WSpace(5), _buildInfo()], children: [_buildAvatar(), const WSpace(5), _buildInfo()],
); ),
}, fallback:
fallback: (context) { (context) => Row(
return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
AppTypography('Выберите коллекцию', type: Bold14px()), AppTypography('Выберите коллекцию', type: Bold14px()),
], ],
); ),
},
), ),
), ),
); );
} }
///
/// Построение основной информации
///
Widget _buildInfo() { Widget _buildInfo() {
return SizedBox( return SizedBox(
width: 230.w, width: 230.w,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: [
_buildTitle(), _buildTitle(),
const HSpace(4), const HSpace(4),
Row( Row(
children: <Widget>[ children: [
Assets.icons.typeCards.image( Assets.icons.typeCards.image(
height: 18.h, height: 18.h,
width: 18.w, width: 18.w,
@@ -329,9 +247,6 @@ class _CreateScreenState extends State<CreateScreen> {
); );
} }
///
/// Название коллекции
///
Widget _buildTitle() { Widget _buildTitle() {
return AppTypography( return AppTypography(
_dto.collection!.title, _dto.collection!.title,
@@ -341,15 +256,11 @@ class _CreateScreenState extends State<CreateScreen> {
); );
} }
///
/// Обложка коллекции
///
Widget _buildAvatar() { Widget _buildAvatar() {
return SizedBox.square( return SizedBox.square(
dimension: 50.r, dimension: 50.r,
child: DecoratedBox( child: DecoratedBox(
decoration: BoxDecoration(shape: BoxShape.circle, color: AppColors.bg), decoration: BoxDecoration(shape: BoxShape.circle, color: AppColors.bg),
child: Wif( child: Wif(
condition: _dto.collection?.image != null, condition: _dto.collection?.image != null,
builder: builder:
@@ -367,4 +278,92 @@ class _CreateScreenState extends State<CreateScreen> {
), ),
); );
} }
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),
);
}
} }