Kapcsolat menü és a hozzá tartozó funkciók.
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../models/contact.dart';
|
||||
import '../../../../services/contact_service.dart';
|
||||
|
||||
/// Kapcsolat szerkesztő — TELJES OLDAL (Scaffold), nem bottom sheet.
|
||||
///
|
||||
/// Miért oldal: a bottom sheet a szoftveres billentyűzettel rosszul
|
||||
/// viselkedik (a mezőket eltakarja / a lapot feltolja). A Scaffold body
|
||||
/// automatikusan a billentyűzet fölé görget, a mentés gomb pedig fixen
|
||||
/// az appbarban van — kesztyűs, terepi használatra is kényelmes.
|
||||
///
|
||||
/// Új rekord: `Get.to(() => const ContactEditView())`.
|
||||
/// Szerkesztés: `Get.to(() => const ContactEditView(), arguments: contact)`.
|
||||
class ContactEditView extends StatefulWidget {
|
||||
const ContactEditView({super.key});
|
||||
|
||||
@override
|
||||
State<ContactEditView> createState() => _ContactEditViewState();
|
||||
}
|
||||
|
||||
class _ContactEditViewState extends State<ContactEditView> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late final Contact? _original;
|
||||
|
||||
late final TextEditingController _name;
|
||||
late final TextEditingController _address;
|
||||
late final TextEditingController _phone;
|
||||
late final TextEditingController _email;
|
||||
late final TextEditingController _note;
|
||||
|
||||
bool _saving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_original = Get.arguments is Contact ? Get.arguments as Contact : null;
|
||||
_name = TextEditingController(text: _original?.name ?? '');
|
||||
_address = TextEditingController(text: _original?.address ?? '');
|
||||
_phone = TextEditingController(text: _original?.phone ?? '');
|
||||
_email = TextEditingController(text: _original?.email ?? '');
|
||||
_note = TextEditingController(text: _original?.note ?? '');
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_name.dispose();
|
||||
_address.dispose();
|
||||
_phone.dispose();
|
||||
_email.dispose();
|
||||
_note.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _save() async {
|
||||
if (!(_formKey.currentState?.validate() ?? false)) return;
|
||||
setState(() => _saving = true);
|
||||
try {
|
||||
final contact = (_original ?? const Contact(name: '')).copyWith(
|
||||
name: _name.text,
|
||||
address: _address.text,
|
||||
phone: _phone.text,
|
||||
email: _email.text,
|
||||
note: _note.text,
|
||||
);
|
||||
final queued = await ContactService.to.save(contact);
|
||||
Get.back(result: queued); // a lista frissítéshez visszakapja
|
||||
Get.snackbar(queued ? 'Elmentve (offline)' : 'Mentve',
|
||||
queued ? '${contact.name} - feltöltés, amint van net' : contact.name,
|
||||
snackPosition: SnackPosition.BOTTOM);
|
||||
} catch (e) {
|
||||
Get.snackbar('Hiba', _friendly(e),
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: const Color(0xFFB71C1C),
|
||||
colorText: const Color(0xFFFFFFFF));
|
||||
} finally {
|
||||
if (mounted) setState(() => _saving = false);
|
||||
}
|
||||
}
|
||||
|
||||
String _friendly(Object e) {
|
||||
final s = e.toString();
|
||||
if (s.contains('permission') ||
|
||||
s.contains('policy') ||
|
||||
s.contains('row-level')) {
|
||||
return 'Nincs jogosultságod a művelethez.';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isNew = _original?.id == null;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(isNew ? 'Új kapcsolat' : 'Kapcsolat szerkesztése'),
|
||||
actions: [
|
||||
TextButton.icon(
|
||||
onPressed: _saving ? null : _save,
|
||||
icon: _saving
|
||||
? const SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Icon(Icons.check),
|
||||
label: const Text('Mentés'),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Form(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _name,
|
||||
autofocus: isNew,
|
||||
textCapitalization: TextCapitalization.words,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Név *',
|
||||
prefixIcon: Icon(Icons.person_outline),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (v) => (v == null || v.trim().isEmpty)
|
||||
? 'A név megadása kötelező.'
|
||||
: null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
controller: _address,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Cím',
|
||||
prefixIcon: Icon(Icons.location_on_outlined),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
controller: _phone,
|
||||
keyboardType: TextInputType.phone,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Telefonszám',
|
||||
prefixIcon: Icon(Icons.phone_outlined),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
controller: _email,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'E-mail',
|
||||
prefixIcon: Icon(Icons.email_outlined),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (v) {
|
||||
if (v == null || v.trim().isEmpty) return null;
|
||||
final ok =
|
||||
RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$').hasMatch(v.trim());
|
||||
return ok ? null : 'Érvénytelen e-mail cím.';
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
controller: _note,
|
||||
maxLines: 4,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Megjegyzés',
|
||||
prefixIcon: Icon(Icons.notes_outlined),
|
||||
alignLabelWithHint: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
FilledButton.icon(
|
||||
onPressed: _saving ? null : _save,
|
||||
icon: const Icon(Icons.save_outlined),
|
||||
label: const Text('Mentés'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user