151 lines
4.8 KiB
Dart
151 lines
4.8 KiB
Dart
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:quasar_jet/models/storage_model.dart';
|
|
import 'package:quasar_jet/services/vpn_service.dart';
|
|
import 'package:quasar_jet/views/config_info_view.dart';
|
|
|
|
// ignore: must_be_immutable
|
|
class SettingsView extends StatefulWidget {
|
|
SettingsView({super.key, required this.model, required this.vpnService});
|
|
|
|
StorageModel model;
|
|
VpnService vpnService;
|
|
|
|
@override
|
|
State<SettingsView> createState() => _SettingsViewState();
|
|
}
|
|
|
|
class _SettingsViewState extends State<SettingsView> {
|
|
final _key = GlobalKey<ExpandableFabState>();
|
|
|
|
Future<void> _changeSelectedItem(int index) async {
|
|
setState(() {
|
|
widget.model.selected = index;
|
|
});
|
|
await widget.vpnService.syncActiveConfig(widget.model);
|
|
}
|
|
|
|
Future<void> _removeItem(int index) async {
|
|
setState(() {
|
|
widget.model.removeConfig(index);
|
|
});
|
|
await widget.vpnService.syncActiveConfig(widget.model);
|
|
}
|
|
|
|
Future<void> _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();
|
|
}
|
|
}
|
|
|
|
void _goToConfigInfo(BuildContext context, int index) {
|
|
Navigator.push(context, MaterialPageRoute(builder: (context) => ConfigInfoView(config: widget.vpnService.parseConfig(widget.model.configs[index].config))));
|
|
}
|
|
|
|
@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),
|
|
onLongPress: () => _goToConfigInfo(context, 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();
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|