Files
Remever/lib/screens/crud_collection/widgets/crud_collection_fullscreen_field.dart

292 lines
7.9 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 'package:auto_route/auto_route.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_keyboard_size/flutter_keyboard_size.dart';
import 'package:remever/common/functions.dart';
import 'package:remever/common/resources.dart';
import 'package:remever/common/widgets/typography.dart';
import 'package:remever/common/widgets/wspace.dart';
import 'package:remever/components/extensions/context.dart';
import 'package:remever/gen/assets.gen.dart';
import 'package:remever/screens/dialogs/alert_dialog.dart';
@RoutePage()
class CrudCollectionFullscreenField extends StatefulWidget {
const CrudCollectionFullscreenField({
super.key,
this.title = '',
this.hint,
this.content,
this.height = 92,
required this.onEditingComplete,
});
final String title;
final double height;
final String? hint;
final String? content;
final void Function(String?) onEditingComplete;
@override
State<CrudCollectionFullscreenField> createState() =>
_CrudCollectionFullscreenFieldState();
}
class _CrudCollectionFullscreenFieldState
extends State<CrudCollectionFullscreenField> {
final TextEditingController _controller = TextEditingController();
@override
void initState() {
super.initState();
if (widget.content != null) {
_controller.text = widget.content!;
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return KeyboardSizeProvider(
child: SafeArea(
top: false,
child: Scaffold(
backgroundColor: AppColors.gray_bg,
appBar: _buildAppBar(),
body: _buildMainBody(),
),
),
);
}
Widget _buildMainBody() {
return Stack(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16).r,
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const HSpace(16),
_buildField(),
if (widget.hint != null) ...[
const HSpace(16),
AppTypography(
widget.hint!,
type: Regular14px(),
color: AppColors.disabled,
),
],
const HSpace(50),
],
),
),
),
Align(alignment: Alignment.bottomCenter, child: _buildMenu()),
],
);
}
Widget _buildMenu() {
return Consumer<ScreenHeight>(
builder: (_, screenHeight, __) {
return AnimatedOpacity(
opacity: 1,
duration: const Duration(milliseconds: 500),
child: Container(
height: 64.h,
decoration: BoxDecoration(
color: AppColors.white,
border: Border(
top: BorderSide(color: AppColors.gray, width: 1.w),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildPasteButton(),
_buildCopyButton(),
_buildSubmitButton(),
],
),
),
);
},
);
}
Widget _buildPasteButton() {
return GestureDetector(
onTap: _onPasteTap,
child: Assets.icons.typePaste.image(height: 24.h, width: 24.w),
);
}
Future<void> _onPasteTap() async {
try {
final data = await Clipboard.getData(Clipboard.kTextPlain);
if (data?.text?.isEmpty ?? true) {
showErrorToast('Не удалось получить текст из буфера обмена');
return;
}
_controller.text += ' ${data!.text}';
showSuccessToast('Текст вставлен из буфера обмена');
} catch (e) {
showErrorToast('Ошибка при вставке текста: $e');
}
}
Widget _buildCopyButton() {
return GestureDetector(
onTap: _onCopyTap,
child: Assets.icons.typeCopy.image(height: 24.h, width: 24.w),
);
}
Future<void> _onCopyTap() async {
if (_controller.text.isEmpty) {
showErrorToast('Нет содержимого для отправки в буфер обмена');
return;
}
try {
await Clipboard.setData(ClipboardData(text: _controller.text));
showSuccessToast('Текст скопирован в буфер обмена');
} catch (e) {
showErrorToast('Ошибка при копировании текста: $e');
}
}
Widget _buildSubmitButton() {
return GestureDetector(
onTap: _onSubmitTap,
child: SizedBox.square(
dimension: 32.r,
child: const DecoratedBox(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColors.primary,
),
child: Center(
child: Icon(Icons.check, color: AppColors.white, size: 24),
),
),
),
);
}
void _onSubmitTap() {
widget.onEditingComplete(_controller.text);
context.back();
}
Widget _buildField() {
return SizedBox(
height: widget.height.h,
child: DecoratedBox(
decoration: BoxDecoration(
color: AppColors.white,
borderRadius: BorderRadius.circular(12).r,
),
child: Padding(
padding: const EdgeInsets.all(12).r,
child: TextField(
autofocus: true,
controller: _controller,
textCapitalization: TextCapitalization.sentences,
maxLines: 99,
maxLength: 250,
cursorColor: AppColors.danger,
decoration: const InputDecoration.collapsed(
hintText: 'Введите содержимое',
hintStyle: TextStyle(color: AppColors.gray),
),
),
),
),
);
}
AppBar _buildAppBar() {
return AppBar(
toolbarHeight: 56.h,
backgroundColor: AppColors.white,
shadowColor: Colors.transparent,
leading: IconButton(
onPressed: () => _handleBackPress(),
icon: const Icon(CupertinoIcons.left_chevron, color: Colors.black),
),
centerTitle: true,
title: AppTypography(
widget.title,
type: SemiBold20px(),
color: AppColors.body_text,
),
actions: [
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<void> _handleBackPress() async {
final shouldExit = await _showExitDialog();
if (shouldExit ?? false) {
context.back();
}
}
Future<bool?> _showExitDialog() async {
final res = await showCuperModalBottomSheet<bool>(
context: context,
height: 262.h,
builder:
(_) => const AlertInfoDialog(
title: 'У вас есть несохраненные изменения',
acceptTitle: 'Выйти',
declineTitle: 'Сохранить и выйти',
),
);
if (res == null) return false;
if (res) return true;
widget.onEditingComplete(_controller.text);
return true;
}
Future<void> _showResetDialog() async {
final res = await showCuperModalBottomSheet<bool>(
context: context,
height: 262.h,
builder:
(_) => AlertInfoDialog(
title: 'Удалить вcе содержимое поля "${widget.title}"?',
acceptTitle: 'Удалить',
declineTitle: 'Отменить',
),
);
if (res == true) {
_controller.clear();
}
}
}