Files
MWClash/lib/views/config/dns.dart
chen08209 6e404ab19c Fix windows some issues
Optimize overwrite handle

Optimize access control page

Optimize some details
2025-12-12 14:33:03 +08:00

667 lines
18 KiB
Dart

import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/providers/config.dart';
import 'package:fl_clash/widgets/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class OverrideItem extends ConsumerWidget {
const OverrideItem({super.key});
@override
Widget build(BuildContext context, ref) {
final override = ref.watch(overrideDnsProvider);
return ListItem.switchItem(
title: Text(appLocalizations.overrideDns),
subtitle: Text(appLocalizations.overrideDnsDesc),
delegate: SwitchDelegate(
value: override,
onChanged: (bool value) async {
ref.read(overrideDnsProvider.notifier).value = value;
},
),
);
}
}
class StatusItem extends ConsumerWidget {
const StatusItem({super.key});
@override
Widget build(BuildContext context, ref) {
final enable = ref.watch(
patchClashConfigProvider.select((state) => state.dns.enable),
);
return ListItem.switchItem(
title: Text(appLocalizations.status),
subtitle: Text(appLocalizations.statusDesc),
delegate: SwitchDelegate(
value: enable,
onChanged: (bool value) async {
ref
.read(patchClashConfigProvider.notifier)
.updateState((state) => state.copyWith.dns(enable: value));
},
),
);
}
}
class ListenItem extends ConsumerWidget {
const ListenItem({super.key});
@override
Widget build(BuildContext context, ref) {
final listen = ref.watch(
patchClashConfigProvider.select((state) => state.dns.listen),
);
return ListItem.input(
title: Text(appLocalizations.listen),
subtitle: Text(listen),
delegate: InputDelegate(
title: appLocalizations.listen,
value: listen,
validator: (value) {
if (value == null || value.isEmpty) {
return appLocalizations.emptyTip(appLocalizations.listen);
}
return null;
},
onChanged: (String? value) {
if (value == null) {
return;
}
ref
.read(patchClashConfigProvider.notifier)
.updateState((state) => state.copyWith.dns(listen: value));
},
),
);
}
}
class PreferH3Item extends ConsumerWidget {
const PreferH3Item({super.key});
@override
Widget build(BuildContext context, ref) {
final preferH3 = ref.watch(
patchClashConfigProvider.select((state) => state.dns.preferH3),
);
return ListItem.switchItem(
title: const Text('PreferH3'),
subtitle: Text(appLocalizations.preferH3Desc),
delegate: SwitchDelegate(
value: preferH3,
onChanged: (bool value) async {
ref
.read(patchClashConfigProvider.notifier)
.updateState((state) => state.copyWith.dns(preferH3: value));
},
),
);
}
}
class IPv6Item extends ConsumerWidget {
const IPv6Item({super.key});
@override
Widget build(BuildContext context, ref) {
final ipv6 = ref.watch(
patchClashConfigProvider.select((state) => state.dns.ipv6),
);
return ListItem.switchItem(
title: const Text('IPv6'),
delegate: SwitchDelegate(
value: ipv6,
onChanged: (bool value) async {
ref
.read(patchClashConfigProvider.notifier)
.updateState((state) => state.copyWith.dns(ipv6: value));
},
),
);
}
}
class RespectRulesItem extends ConsumerWidget {
const RespectRulesItem({super.key});
@override
Widget build(BuildContext context, ref) {
final respectRules = ref.watch(
patchClashConfigProvider.select((state) => state.dns.respectRules),
);
return ListItem.switchItem(
title: Text(appLocalizations.respectRules),
subtitle: Text(appLocalizations.respectRulesDesc),
delegate: SwitchDelegate(
value: respectRules,
onChanged: (bool value) async {
ref
.read(patchClashConfigProvider.notifier)
.updateState((state) => state.copyWith.dns(respectRules: value));
},
),
);
}
}
class DnsModeItem extends ConsumerWidget {
const DnsModeItem({super.key});
@override
Widget build(BuildContext context, ref) {
final enhancedMode = ref.watch(
patchClashConfigProvider.select((state) => state.dns.enhancedMode),
);
return ListItem<DnsMode>.options(
title: Text(appLocalizations.dnsMode),
subtitle: Text(enhancedMode.name),
delegate: OptionsDelegate(
title: appLocalizations.dnsMode,
options: DnsMode.values,
onChanged: (value) {
if (value == null) {
return;
}
ref
.read(patchClashConfigProvider.notifier)
.updateState((state) => state.copyWith.dns(enhancedMode: value));
},
textBuilder: (dnsMode) => dnsMode.name,
value: enhancedMode,
),
);
}
}
class FakeIpRangeItem extends ConsumerWidget {
const FakeIpRangeItem({super.key});
@override
Widget build(BuildContext context, ref) {
final fakeIpRange = ref.watch(
patchClashConfigProvider.select((state) => state.dns.fakeIpRange),
);
return ListItem.input(
title: Text(appLocalizations.fakeipRange),
subtitle: Text(fakeIpRange),
delegate: InputDelegate(
title: appLocalizations.fakeipRange,
value: fakeIpRange,
validator: (value) {
if (value == null || value.isEmpty) {
return appLocalizations.emptyTip(appLocalizations.fakeipRange);
}
return null;
},
onChanged: (String? value) {
if (value == null) {
return;
}
ref
.read(patchClashConfigProvider.notifier)
.updateState((state) => state.copyWith.dns(fakeIpRange: value));
},
),
);
}
}
class FakeIpFilterItem extends ConsumerWidget {
const FakeIpFilterItem({super.key});
@override
Widget build(BuildContext context, ref) {
final fakeIpFilter = ref.watch(
patchClashConfigProvider.select((state) => state.dns.fakeIpFilter),
);
return ListItem.open(
title: Text(appLocalizations.fakeipFilter),
delegate: OpenDelegate(
blur: false,
widget: ListInputPage(
title: appLocalizations.fakeipFilter,
items: fakeIpFilter,
titleBuilder: (item) => Text(item),
),
onChanged: (items) {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) => state.copyWith.dns(fakeIpFilter: List.from(items)),
);
},
),
);
}
}
class DefaultNameserverItem extends ConsumerWidget {
const DefaultNameserverItem({super.key});
@override
Widget build(BuildContext context, ref) {
final defaultNameserver = ref.watch(
patchClashConfigProvider.select((state) => state.dns.defaultNameserver),
);
return ListItem.open(
title: Text(appLocalizations.defaultNameserver),
subtitle: Text(appLocalizations.defaultNameserverDesc),
delegate: OpenDelegate(
blur: false,
widget: ListInputPage(
title: appLocalizations.defaultNameserver,
items: defaultNameserver,
titleBuilder: (item) => Text(item),
),
onChanged: (items) {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) =>
state.copyWith.dns(defaultNameserver: List.from(items)),
);
},
),
);
}
}
class NameserverItem extends ConsumerWidget {
const NameserverItem({super.key});
@override
Widget build(BuildContext context, ref) {
final nameserver = ref.watch(
patchClashConfigProvider.select((state) => state.dns.nameserver),
);
return ListItem.open(
title: Text(appLocalizations.nameserver),
subtitle: Text(appLocalizations.nameserverDesc),
delegate: OpenDelegate(
blur: false,
widget: ListInputPage(
title: appLocalizations.nameserver,
items: nameserver,
titleBuilder: (item) => Text(item),
),
onChanged: (items) {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) => state.copyWith.dns(nameserver: List.from(items)),
);
},
),
);
}
}
class UseHostsItem extends ConsumerWidget {
const UseHostsItem({super.key});
@override
Widget build(BuildContext context, ref) {
final useHosts = ref.watch(
patchClashConfigProvider.select((state) => state.dns.useHosts),
);
return ListItem.switchItem(
title: Text(appLocalizations.useHosts),
delegate: SwitchDelegate(
value: useHosts,
onChanged: (bool value) async {
ref
.read(patchClashConfigProvider.notifier)
.updateState((state) => state.copyWith.dns(useHosts: value));
},
),
);
}
}
class UseSystemHostsItem extends ConsumerWidget {
const UseSystemHostsItem({super.key});
@override
Widget build(BuildContext context, ref) {
final useSystemHosts = ref.watch(
patchClashConfigProvider.select((state) => state.dns.useSystemHosts),
);
return ListItem.switchItem(
title: Text(appLocalizations.useSystemHosts),
delegate: SwitchDelegate(
value: useSystemHosts,
onChanged: (bool value) async {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) => state.copyWith.dns(useSystemHosts: value),
);
},
),
);
}
}
class NameserverPolicyItem extends ConsumerWidget {
const NameserverPolicyItem({super.key});
@override
Widget build(BuildContext context, ref) {
final nameserverPolicy = ref.watch(
patchClashConfigProvider.select((state) => state.dns.nameserverPolicy),
);
return ListItem.open(
title: Text(appLocalizations.nameserverPolicy),
subtitle: Text(appLocalizations.nameserverPolicyDesc),
delegate: OpenDelegate(
blur: false,
widget: MapInputPage(
title: appLocalizations.nameserverPolicy,
map: nameserverPolicy,
titleBuilder: (item) => Text(item.key),
subtitleBuilder: (item) => Text(item.value),
),
onChanged: (value) {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) => state.copyWith.dns(nameserverPolicy: value),
);
},
),
);
}
}
class ProxyServerNameserverItem extends ConsumerWidget {
const ProxyServerNameserverItem({super.key});
@override
Widget build(BuildContext context, ref) {
final proxyServerNameserver = ref.watch(
patchClashConfigProvider.select(
(state) => state.dns.proxyServerNameserver,
),
);
return ListItem.open(
title: Text(appLocalizations.proxyNameserver),
subtitle: Text(appLocalizations.proxyNameserverDesc),
delegate: OpenDelegate(
blur: false,
widget: ListInputPage(
title: appLocalizations.proxyNameserver,
items: proxyServerNameserver,
titleBuilder: (item) => Text(item),
),
onChanged: (items) {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) =>
state.copyWith.dns(proxyServerNameserver: List.from(items)),
);
},
),
);
}
}
class FallbackItem extends ConsumerWidget {
const FallbackItem({super.key});
@override
Widget build(BuildContext context, ref) {
final fallback = ref.watch(
patchClashConfigProvider.select((state) => state.dns.fallback),
);
return ListItem.open(
title: Text(appLocalizations.fallback),
subtitle: Text(appLocalizations.fallbackDesc),
delegate: OpenDelegate(
blur: false,
widget: ListInputPage(
title: appLocalizations.fallback,
items: fallback,
titleBuilder: (item) => Text(item),
),
onChanged: (items) {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) => state.copyWith.dns(fallback: List.from(items)),
);
},
),
);
}
}
class GeoipItem extends ConsumerWidget {
const GeoipItem({super.key});
@override
Widget build(BuildContext context, ref) {
final geoip = ref.watch(
patchClashConfigProvider.select(
(state) => state.dns.fallbackFilter.geoip,
),
);
return ListItem.switchItem(
title: const Text('Geoip'),
delegate: SwitchDelegate(
value: geoip,
onChanged: (bool value) async {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) => state.copyWith.dns.fallbackFilter(geoip: value),
);
},
),
);
}
}
class GeoipCodeItem extends ConsumerWidget {
const GeoipCodeItem({super.key});
@override
Widget build(BuildContext context, ref) {
final geoipCode = ref.watch(
patchClashConfigProvider.select(
(state) => state.dns.fallbackFilter.geoipCode,
),
);
return ListItem.input(
title: Text(appLocalizations.geoipCode),
subtitle: Text(geoipCode),
delegate: InputDelegate(
title: appLocalizations.geoipCode,
value: geoipCode,
validator: (value) {
if (value == null || value.isEmpty) {
return appLocalizations.emptyTip(appLocalizations.geoipCode);
}
return null;
},
onChanged: (String? value) {
if (value == null) {
return;
}
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) => state.copyWith.dns.fallbackFilter(geoipCode: value),
);
},
),
);
}
}
class GeositeItem extends ConsumerWidget {
const GeositeItem({super.key});
@override
Widget build(BuildContext context, ref) {
final geosite = ref.watch(
patchClashConfigProvider.select(
(state) => state.dns.fallbackFilter.geosite,
),
);
return ListItem.open(
title: const Text('Geosite'),
delegate: OpenDelegate(
blur: false,
widget: ListInputPage(
title: 'Geosite',
items: geosite,
titleBuilder: (item) => Text(item),
),
onChanged: (items) {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) => state.copyWith.dns.fallbackFilter(
geosite: List.from(items),
),
);
},
),
);
}
}
class IpcidrItem extends ConsumerWidget {
const IpcidrItem({super.key});
@override
Widget build(BuildContext context, ref) {
final ipcidr = ref.watch(
patchClashConfigProvider.select(
(state) => state.dns.fallbackFilter.ipcidr,
),
);
return ListItem.open(
title: Text(appLocalizations.ipcidr),
delegate: OpenDelegate(
blur: false,
widget: ListInputPage(
title: appLocalizations.ipcidr,
items: ipcidr,
titleBuilder: (item) => Text(item),
),
onChanged: (items) {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) =>
state.copyWith.dns.fallbackFilter(ipcidr: List.from(items)),
);
},
),
);
}
}
class DomainItem extends ConsumerWidget {
const DomainItem({super.key});
@override
Widget build(BuildContext context, ref) {
final domain = ref.watch(
patchClashConfigProvider.select(
(state) => state.dns.fallbackFilter.domain,
),
);
return ListItem.open(
title: Text(appLocalizations.domain),
delegate: OpenDelegate(
blur: false,
widget: ListInputPage(
title: appLocalizations.domain,
items: domain,
titleBuilder: (item) => Text(item),
),
onChanged: (items) {
ref
.read(patchClashConfigProvider.notifier)
.updateState(
(state) =>
state.copyWith.dns.fallbackFilter(domain: List.from(items)),
);
},
),
);
}
}
class DnsOptions extends StatelessWidget {
const DnsOptions({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: generateSection(
title: appLocalizations.options,
items: [
const StatusItem(),
const ListenItem(),
const UseHostsItem(),
const UseSystemHostsItem(),
const IPv6Item(),
const RespectRulesItem(),
const PreferH3Item(),
const DnsModeItem(),
const FakeIpRangeItem(),
const FakeIpFilterItem(),
const DefaultNameserverItem(),
const NameserverPolicyItem(),
const NameserverItem(),
const FallbackItem(),
const ProxyServerNameserverItem(),
],
),
);
}
}
class FallbackFilterOptions extends StatelessWidget {
const FallbackFilterOptions({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: generateSection(
title: appLocalizations.fallbackFilter,
items: [
const GeoipItem(),
const GeoipCodeItem(),
const GeositeItem(),
const IpcidrItem(),
const DomainItem(),
],
),
);
}
}
const dnsItems = <Widget>[
OverrideItem(),
DnsOptions(),
FallbackFilterOptions(),
];
class DnsListView extends ConsumerWidget {
const DnsListView({super.key});
@override
Widget build(BuildContext context, ref) {
return generateListView(dnsItems);
}
}