Files
ignis_app/lib/screens/home_edit_screen.dart
2026-04-02 23:51:28 +07:00

223 lines
7.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../models/home_config.dart';
import '../providers/providers.dart';
/// Экран создания или редактирования "дома" (сервера Ignis).
class HomeEditScreen extends ConsumerStatefulWidget {
final HomeConfig? home; // null -- создание, иначе редактирование
const HomeEditScreen({super.key, this.home});
@override
ConsumerState<HomeEditScreen> createState() => _HomeEditScreenState();
}
class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
final _nameCtrl = TextEditingController();
final _urlCtrl = TextEditingController();
final _keyCtrl = TextEditingController();
final _latCtrl = TextEditingController();
final _lonCtrl = TextEditingController();
bool _saving = false;
bool get _isEdit => widget.home != null;
@override
void initState() {
super.initState();
if (_isEdit) {
_nameCtrl.text = widget.home!.name;
_urlCtrl.text = widget.home!.url;
_keyCtrl.text = widget.home!.apiKey;
if (widget.home!.latitude != null) {
_latCtrl.text = widget.home!.latitude.toString();
}
if (widget.home!.longitude != null) {
_lonCtrl.text = widget.home!.longitude.toString();
}
}
}
@override
void dispose() {
_nameCtrl.dispose();
_urlCtrl.dispose();
_keyCtrl.dispose();
_latCtrl.dispose();
_lonCtrl.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_isEdit ? 'РЕДАКТИРОВАТЬ ДОМ' : 'НОВЫЙ ДОМ'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: _nameCtrl,
decoration: const InputDecoration(
labelText: 'Название (например "Квартира")',
prefixIcon: Icon(Icons.home),
),
textCapitalization: TextCapitalization.sentences,
),
const SizedBox(height: 12),
TextField(
controller: _urlCtrl,
decoration: const InputDecoration(
labelText: 'Адрес сервера (например ignis.akokos.ru)',
prefixIcon: Icon(Icons.dns),
),
keyboardType: TextInputType.url,
),
const SizedBox(height: 12),
TextField(
controller: _keyCtrl,
decoration: const InputDecoration(
labelText: 'API Key',
prefixIcon: Icon(Icons.key),
),
obscureText: true,
),
const SizedBox(height: 24),
// ─── GPS-координаты (опционально) ───
const Text(
'Координаты дома (опционально)',
style: TextStyle(
color: Colors.white54,
fontSize: 13,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
const Text(
'Для автоматизации по геолокации',
style: TextStyle(color: Colors.white30, fontSize: 12),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: TextField(
controller: _latCtrl,
decoration: const InputDecoration(
labelText: 'Широта',
prefixIcon: Icon(Icons.location_on, size: 20),
hintText: '51.128',
),
keyboardType: const TextInputType.numberWithOptions(
decimal: true, signed: true),
),
),
const SizedBox(width: 12),
Expanded(
child: TextField(
controller: _lonCtrl,
decoration: const InputDecoration(
labelText: 'Долгота',
prefixIcon: Icon(Icons.location_on, size: 20),
hintText: '71.430',
),
keyboardType: const TextInputType.numberWithOptions(
decimal: true, signed: true),
),
),
],
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
height: 48,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepOrange,
foregroundColor: Colors.white,
),
onPressed: _saving ? null : _save,
child: _saving
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: Text(_isEdit ? 'СОХРАНИТЬ' : 'ДОБАВИТЬ'),
),
),
// Отступ внизу для системных кнопок
SizedBox(height: MediaQuery.of(context).padding.bottom + 16),
],
),
),
);
}
Future<void> _save() async {
final name = _nameCtrl.text.trim();
final url = _urlCtrl.text.trim();
final key = _keyCtrl.text.trim();
final latText = _latCtrl.text.trim();
final lonText = _lonCtrl.text.trim();
if (name.isEmpty || url.isEmpty || key.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Заполните все обязательные поля')),
);
return;
}
double? lat;
double? lon;
if (latText.isNotEmpty && lonText.isNotEmpty) {
lat = double.tryParse(latText);
lon = double.tryParse(lonText);
if (lat == null || lon == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Некорректные координаты')),
);
return;
}
}
setState(() => _saving = true);
final home = _isEdit
? widget.home!.copyWith(
name: name,
url: url,
apiKey: key,
latitude: lat,
longitude: lon,
clearCoordinates: latText.isEmpty && lonText.isEmpty,
)
: HomeConfig(
id: DateTime.now().millisecondsSinceEpoch.toString(),
name: name,
url: url,
apiKey: key,
latitude: lat,
longitude: lon,
);
if (_isEdit) {
await ref.read(homesProvider.notifier).update(home);
} else {
await ref.read(homesProvider.notifier).add(home);
}
if (mounted) Navigator.of(context).pop();
}
}