import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:ionicons/ionicons.dart'; import 'package:vpn/models/storage_model.dart'; import 'package:vpn/services/vpn_service.dart'; // ignore: must_be_immutable class SettingsView extends StatefulWidget { SettingsView({super.key, required this.model, required this.vpnService}); StorageModel model; VpnService vpnService; @override State createState() => _SettingsViewState(); } class _SettingsViewState extends State { final _key = GlobalKey(); Future _changeSelectedItem(int index) async { setState(() { widget.model.selected = index; }); await widget.vpnService.syncActiveConfig(widget.model); } Future _removeItem(int index) async { setState(() { widget.model.removeConfig(index); }); await widget.vpnService.syncActiveConfig(widget.model); } Future _addItemFromClipboard(BuildContext context) async { final data = await Clipboard.getData(Clipboard.kTextPlain); if (!context.mounted) return; final String config = data?.text?.trim() ?? ''; if (config.isEmpty) { ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('Буфер обмена пуст'))); return; } final String? name = widget.vpnService.getName(config); if (name == null) { ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('Ошибка импорта'))); return; } setState(() { widget.model.addConfig(name, config); }); await widget.vpnService.syncActiveConfig(widget.model); if (!context.mounted) return; ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('Конфигурация импортирована'))); } void _closeFab() { final state = _key.currentState; if (state != null && state.isOpen) { state.toggle(); } } @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Scaffold( appBar: AppBar(title: const Text("Settings"), centerTitle: true), body: ListView.separated( padding: const EdgeInsets.all(16), itemCount: widget.model.configs.length + 1, separatorBuilder: (_, _) => const SizedBox(height: 10), itemBuilder: (context, index) { if (index == widget.model.configs.length) { return const SizedBox(height: 40); } return Row( children: [ Expanded( child: Container( decoration: BoxDecoration( color: Theme.of(context).hoverColor, borderRadius: BorderRadius.circular(8), ), child: ListTile( leading: widget.model.selected == index ? Icon(Ionicons.checkmark) : null, title: Text(widget.model.configs[index].name), onTap: () async => _changeSelectedItem(index), ), ), ), const SizedBox(width: 8), IconButton.filled( onPressed: () async => _removeItem(index), icon: const Icon(Ionicons.trash), ), ], ); }, ), floatingActionButtonLocation: ExpandableFab.location, floatingActionButton: ExpandableFab( key: _key, openButtonBuilder: RotateFloatingActionButtonBuilder( backgroundColor: colorScheme.primary, foregroundColor: colorScheme.onPrimary, child: const Icon(Ionicons.add), ), closeButtonBuilder: RotateFloatingActionButtonBuilder( backgroundColor: colorScheme.primary, foregroundColor: colorScheme.onPrimary, child: const Icon(Ionicons.close), ), children: [ FloatingActionButton.extended( heroTag: null, foregroundColor: colorScheme.onPrimary, backgroundColor: colorScheme.primary, icon: const Icon(Ionicons.clipboard), label: const Text("From clipboard"), onPressed: () { _addItemFromClipboard(context); _closeFab(); }, ), ], ), ); } }