Files
Remever/lib/screens/create_card/create_screen.dart

370 lines
11 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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: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/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';
@RoutePage()
class CreateScreen extends StatefulWidget {
const CreateScreen({super.key});
@override
State<CreateScreen> createState() => _CreateScreenState();
}
class _CreateScreenState extends State<CreateScreen> {
CreateTicketDto _dto = CreateTicketDto();
// Constants for spacing and dimensions
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) {
showErrorToast('Файл не выбран');
return;
}
final filePath = result.files.single.path;
if (filePath == null) {
showErrorToast('Не удалось получить путь к файлу');
return;
}
final file = File(filePath);
final bytes = await file.readAsBytes();
safeSetState(() {
_dto =
isQuestion
? _dto.copyWith(questionImage: bytes)
: _dto.copyWith(answerImage: bytes);
});
}
void _onCollectionTap() {
context.pushRoute(
CollectionSearchRoute(
onCollectionSelect: (collection) {
safeSetState(() => _dto = _dto.copyWith(collection: collection));
},
),
);
}
Future<void> _onCreateTap() async {
if (_dto.collection == null ||
_dto.answer == null ||
_dto.question == null) {
showErrorToast('Необходимо заполнить все поля');
return;
}
await getIt<TicketsInterface>().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);
});
}
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.memory(_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),
);
}
}