150 lines
5.1 KiB
Dart
150 lines
5.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:provider/provider.dart';
|
|
import '../models/instruction.dart';
|
|
import '../providers/instruction_provider.dart';
|
|
import '../widgets/tag_selection_dialog.dart';
|
|
|
|
class AddEditInstructionPage extends StatefulWidget {
|
|
final Instruction? initialInstruction;
|
|
|
|
const AddEditInstructionPage({super.key, this.initialInstruction});
|
|
|
|
@override
|
|
State<AddEditInstructionPage> createState() => _AddEditInstructionPageState();
|
|
}
|
|
|
|
class _AddEditInstructionPageState extends State<AddEditInstructionPage> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
late TextEditingController _titleController;
|
|
late TextEditingController _contentController;
|
|
late List<String> _selectedTags;
|
|
|
|
bool get _isEditing => widget.initialInstruction != null;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_titleController = TextEditingController(text: widget.initialInstruction?.title ?? '');
|
|
_contentController = TextEditingController(text: widget.initialInstruction?.content ?? '');
|
|
_selectedTags = List<String>.from(widget.initialInstruction?.tags ?? []);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_titleController.dispose();
|
|
_contentController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> _showTagSelectionDialog() async {
|
|
final provider = context.read<InstructionProvider>();
|
|
final result = await showDialog<List<String>>(
|
|
context: context,
|
|
builder: (ctx) => TagSelectionDialog(
|
|
allTags: provider.allAvailableTags,
|
|
initialSelectedTags: _selectedTags.toSet(),
|
|
),
|
|
);
|
|
|
|
if (result != null) {
|
|
setState(() {
|
|
_selectedTags = result;
|
|
});
|
|
}
|
|
}
|
|
|
|
Future<void> _saveForm() async {
|
|
if (_formKey.currentState!.validate()) {
|
|
final provider = context.read<InstructionProvider>();
|
|
final title = _titleController.text;
|
|
final content = _contentController.text;
|
|
|
|
showDialog(
|
|
context: context,
|
|
barrierDismissible: false,
|
|
builder: (ctx) => const Center(child: CircularProgressIndicator()));
|
|
|
|
try {
|
|
if (_isEditing) {
|
|
final updatedInstruction = widget.initialInstruction!.copyWith(
|
|
title: title,
|
|
content: content,
|
|
tags: _selectedTags,
|
|
);
|
|
await provider.updateInstruction(updatedInstruction);
|
|
} else {
|
|
await provider.addInstruction(title, content, _selectedTags);
|
|
}
|
|
if (mounted) {
|
|
Navigator.of(context)..pop()..pop();
|
|
}
|
|
} catch (e) {
|
|
if(mounted) {
|
|
Navigator.of(context).pop();
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(content: Text('Ошибка сохранения: $e')),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(_isEditing ? 'Редактировать' : 'Новый инструктаж'),
|
|
actions: [IconButton(icon: const Icon(Icons.save), onPressed: _saveForm)],
|
|
),
|
|
body: Padding(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Form(
|
|
key: _formKey,
|
|
child: ListView(
|
|
children: [
|
|
TextFormField(
|
|
controller: _titleController,
|
|
decoration: const InputDecoration(labelText: 'Название', border: OutlineInputBorder()),
|
|
validator: (v) => v == null || v.isEmpty ? 'Название не может быть пустым' : null,
|
|
),
|
|
const SizedBox(height: 16),
|
|
TextFormField(
|
|
controller: _contentController,
|
|
decoration: const InputDecoration(labelText: 'Содержание', border: OutlineInputBorder()),
|
|
maxLines: 8,
|
|
validator: (v) => v == null || v.isEmpty ? 'Содержание не может быть пустым' : null,
|
|
),
|
|
const SizedBox(height: 24),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
const Text('Теги:', style: TextStyle(fontSize: 16)),
|
|
OutlinedButton.icon(
|
|
icon: const Icon(Icons.edit_note),
|
|
label: const Text('Изменить теги'),
|
|
onPressed: _showTagSelectionDialog,
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 8),
|
|
Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
border: Border.all(color: Colors.grey.shade400),
|
|
borderRadius: BorderRadius.circular(4),
|
|
),
|
|
child: Wrap(
|
|
spacing: 8.0,
|
|
runSpacing: 4.0,
|
|
children: _selectedTags.isEmpty
|
|
? [const Text('Теги не выбраны')]
|
|
: _selectedTags.map((tag) => Chip(label: Text(tag))).toList(),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
} |