Support core status check and force restart Optimize proxies page and access page Update flutter and pub dependencies Update go version Optimize more details
330 lines
8.7 KiB
Dart
330 lines
8.7 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:fl_clash/common/common.dart';
|
|
import 'package:fl_clash/l10n/l10n.dart';
|
|
import 'package:fl_clash/models/models.dart';
|
|
import 'package:fl_clash/providers/providers.dart';
|
|
import 'package:fl_clash/state.dart';
|
|
import 'package:fl_clash/views/about.dart';
|
|
import 'package:fl_clash/views/access.dart';
|
|
import 'package:fl_clash/views/application_setting.dart';
|
|
import 'package:fl_clash/views/config/config.dart';
|
|
import 'package:fl_clash/views/hotkey.dart';
|
|
import 'package:fl_clash/widgets/widgets.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:path/path.dart' show dirname, join;
|
|
|
|
import 'backup_and_recovery.dart';
|
|
import 'developer.dart';
|
|
import 'theme.dart';
|
|
|
|
class ToolsView extends ConsumerStatefulWidget {
|
|
const ToolsView({super.key});
|
|
|
|
@override
|
|
ConsumerState<ToolsView> createState() => _ToolViewState();
|
|
}
|
|
|
|
class _ToolViewState extends ConsumerState<ToolsView> {
|
|
Widget _buildNavigationMenuItem(NavigationItem navigationItem) {
|
|
return ListItem.open(
|
|
leading: navigationItem.icon,
|
|
title: Text(Intl.message(navigationItem.label.name)),
|
|
subtitle: navigationItem.description != null
|
|
? Text(Intl.message(navigationItem.description!))
|
|
: null,
|
|
delegate: OpenDelegate(
|
|
title: Intl.message(navigationItem.label.name),
|
|
widget: navigationItem.builder(context),
|
|
wrap: false,
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildNavigationMenu(List<NavigationItem> navigationItems) {
|
|
return Column(
|
|
children: [
|
|
for (final navigationItem in navigationItems) ...[
|
|
_buildNavigationMenuItem(navigationItem),
|
|
navigationItems.last != navigationItem
|
|
? const Divider(height: 0)
|
|
: Container(),
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
List<Widget> _getOtherList(bool enableDeveloperMode) {
|
|
return generateSection(
|
|
title: appLocalizations.other,
|
|
items: [
|
|
_DisclaimerItem(),
|
|
if (enableDeveloperMode) _DeveloperItem(),
|
|
_InfoItem(),
|
|
],
|
|
);
|
|
}
|
|
|
|
List<Widget> _getSettingList() {
|
|
return generateSection(
|
|
title: appLocalizations.settings,
|
|
items: [
|
|
_LocaleItem(),
|
|
_ThemeItem(),
|
|
_BackupItem(),
|
|
if (system.isDesktop) _HotkeyItem(),
|
|
if (system.isWindows) _LoopbackItem(),
|
|
if (system.isAndroid) _AccessItem(),
|
|
_ConfigItem(),
|
|
_SettingItem(),
|
|
],
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final vm2 = ref.watch(
|
|
appSettingProvider.select(
|
|
(state) => VM2(a: state.locale, b: state.developerMode),
|
|
),
|
|
);
|
|
final items = [
|
|
Consumer(
|
|
builder: (_, ref, _) {
|
|
final state = ref.watch(moreToolsSelectorStateProvider);
|
|
if (state.navigationItems.isEmpty) {
|
|
return Container();
|
|
}
|
|
return Column(
|
|
children: [
|
|
ListHeader(title: appLocalizations.more),
|
|
_buildNavigationMenu(state.navigationItems),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
..._getSettingList(),
|
|
..._getOtherList(vm2.b),
|
|
];
|
|
return CommonScaffold(
|
|
title: appLocalizations.tools,
|
|
body: ListView.builder(
|
|
key: toolsStoreKey,
|
|
itemCount: items.length,
|
|
itemBuilder: (_, index) => items[index],
|
|
padding: const EdgeInsets.only(bottom: 20),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _LocaleItem extends ConsumerWidget {
|
|
const _LocaleItem();
|
|
|
|
String _getLocaleString(Locale? locale) {
|
|
if (locale == null) return appLocalizations.defaultText;
|
|
return Intl.message(locale.toString());
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final locale = ref.watch(
|
|
appSettingProvider.select((state) => state.locale),
|
|
);
|
|
final subTitle = locale ?? appLocalizations.defaultText;
|
|
final currentLocale = utils.getLocaleForString(locale);
|
|
return ListItem<Locale?>.options(
|
|
leading: const Icon(Icons.language_outlined),
|
|
title: Text(appLocalizations.language),
|
|
subtitle: Text(Intl.message(subTitle)),
|
|
delegate: OptionsDelegate(
|
|
title: appLocalizations.language,
|
|
options: [null, ...AppLocalizations.delegate.supportedLocales],
|
|
onChanged: (Locale? locale) {
|
|
ref
|
|
.read(appSettingProvider.notifier)
|
|
.updateState(
|
|
(state) => state.copyWith(locale: locale?.toString()),
|
|
);
|
|
},
|
|
textBuilder: (locale) => _getLocaleString(locale),
|
|
value: currentLocale,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _ThemeItem extends StatelessWidget {
|
|
const _ThemeItem();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
leading: const Icon(Icons.style),
|
|
title: Text(appLocalizations.theme),
|
|
subtitle: Text(appLocalizations.themeDesc),
|
|
delegate: OpenDelegate(
|
|
title: appLocalizations.theme,
|
|
widget: const ThemeView(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _BackupItem extends StatelessWidget {
|
|
const _BackupItem();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
leading: const Icon(Icons.cloud_sync),
|
|
title: Text(appLocalizations.backupAndRecovery),
|
|
subtitle: Text(appLocalizations.backupAndRecoveryDesc),
|
|
delegate: OpenDelegate(
|
|
title: appLocalizations.backupAndRecovery,
|
|
widget: const BackupAndRecovery(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _HotkeyItem extends StatelessWidget {
|
|
const _HotkeyItem();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
leading: const Icon(Icons.keyboard),
|
|
title: Text(appLocalizations.hotkeyManagement),
|
|
subtitle: Text(appLocalizations.hotkeyManagementDesc),
|
|
delegate: OpenDelegate(
|
|
title: appLocalizations.hotkeyManagement,
|
|
widget: const HotKeyView(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _LoopbackItem extends StatelessWidget {
|
|
const _LoopbackItem();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem(
|
|
leading: const Icon(Icons.lock),
|
|
title: Text(appLocalizations.loopback),
|
|
subtitle: Text(appLocalizations.loopbackDesc),
|
|
onTap: () {
|
|
windows?.runas(
|
|
'"${join(dirname(Platform.resolvedExecutable), "EnableLoopback.exe")}"',
|
|
'',
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class _AccessItem extends StatelessWidget {
|
|
const _AccessItem();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
leading: const Icon(Icons.view_list),
|
|
title: Text(appLocalizations.accessControl),
|
|
subtitle: Text(appLocalizations.accessControlDesc),
|
|
delegate: OpenDelegate(
|
|
title: appLocalizations.appAccessControl,
|
|
widget: const AccessView(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _ConfigItem extends StatelessWidget {
|
|
const _ConfigItem();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
leading: const Icon(Icons.edit),
|
|
title: Text(appLocalizations.basicConfig),
|
|
subtitle: Text(appLocalizations.basicConfigDesc),
|
|
delegate: OpenDelegate(
|
|
title: appLocalizations.basicConfig,
|
|
widget: const ConfigView(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _SettingItem extends StatelessWidget {
|
|
const _SettingItem();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
leading: const Icon(Icons.settings),
|
|
title: Text(appLocalizations.application),
|
|
subtitle: Text(appLocalizations.applicationDesc),
|
|
delegate: OpenDelegate(
|
|
title: appLocalizations.application,
|
|
widget: const ApplicationSettingView(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _DisclaimerItem extends StatelessWidget {
|
|
const _DisclaimerItem();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem(
|
|
leading: const Icon(Icons.gavel),
|
|
title: Text(appLocalizations.disclaimer),
|
|
onTap: () async {
|
|
final isDisclaimerAccepted = await globalState.appController
|
|
.showDisclaimer();
|
|
if (!isDisclaimerAccepted) {
|
|
globalState.appController.handleExit();
|
|
}
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class _InfoItem extends StatelessWidget {
|
|
const _InfoItem();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
leading: const Icon(Icons.info),
|
|
title: Text(appLocalizations.about),
|
|
delegate: OpenDelegate(
|
|
title: appLocalizations.about,
|
|
widget: const AboutView(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _DeveloperItem extends StatelessWidget {
|
|
const _DeveloperItem();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
leading: const Icon(Icons.developer_board),
|
|
title: Text(appLocalizations.developerMode),
|
|
delegate: OpenDelegate(
|
|
title: appLocalizations.developerMode,
|
|
widget: const DeveloperView(),
|
|
),
|
|
);
|
|
}
|
|
}
|