Fix core crash caused by windows resource manager restart Optimize logs, requests, access to pages Fix macos bypass domain issues
739 lines
22 KiB
Dart
739 lines
22 KiB
Dart
import 'package:collection/collection.dart';
|
|
import 'package:fl_clash/common/common.dart';
|
|
import 'package:fl_clash/enum/enum.dart';
|
|
import 'package:fl_clash/models/models.dart';
|
|
import 'package:fl_clash/state.dart';
|
|
import 'package:fl_clash/widgets/widgets.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
class OverrideItem extends StatelessWidget {
|
|
const OverrideItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<Config, bool>(
|
|
selector: (_, config) => config.overrideDns,
|
|
builder: (_, override, __) {
|
|
return ListItem.switchItem(
|
|
title: Text(appLocalizations.overrideDns),
|
|
subtitle: Text(appLocalizations.overrideDnsDesc),
|
|
delegate: SwitchDelegate(
|
|
value: override,
|
|
onChanged: (bool value) async {
|
|
final config = globalState.appController.config;
|
|
config.overrideDns = value;
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class StatusItem extends StatelessWidget {
|
|
const StatusItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<ClashConfig, bool>(
|
|
selector: (_, clashConfig) => clashConfig.dns.enable,
|
|
builder: (_, enable, __) {
|
|
return ListItem.switchItem(
|
|
title: Text(appLocalizations.status),
|
|
subtitle: Text(appLocalizations.statusDesc),
|
|
delegate: SwitchDelegate(
|
|
value: enable,
|
|
onChanged: (bool value) async {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
enable: value,
|
|
);
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class PreferH3Item extends StatelessWidget {
|
|
const PreferH3Item({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<ClashConfig, bool>(
|
|
selector: (_, clashConfig) => clashConfig.dns.preferH3,
|
|
builder: (_, preferH3, __) {
|
|
return ListItem.switchItem(
|
|
title: const Text("PreferH3"),
|
|
subtitle: Text(appLocalizations.preferH3Desc),
|
|
delegate: SwitchDelegate(
|
|
value: preferH3,
|
|
onChanged: (bool value) async {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
preferH3: value,
|
|
);
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class IPv6Item extends StatelessWidget {
|
|
const IPv6Item({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<ClashConfig, bool>(
|
|
selector: (_, clashConfig) => clashConfig.dns.ipv6,
|
|
builder: (_, ipv6, __) {
|
|
return ListItem.switchItem(
|
|
title: const Text("IPv6"),
|
|
delegate: SwitchDelegate(
|
|
value: ipv6,
|
|
onChanged: (bool value) async {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
ipv6: value,
|
|
);
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class RespectRulesItem extends StatelessWidget {
|
|
const RespectRulesItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<ClashConfig, bool>(
|
|
selector: (_, clashConfig) => clashConfig.dns.respectRules,
|
|
builder: (_, respectRules, __) {
|
|
return ListItem.switchItem(
|
|
title: Text(appLocalizations.respectRules),
|
|
subtitle: Text(appLocalizations.respectRulesDesc),
|
|
delegate: SwitchDelegate(
|
|
value: respectRules,
|
|
onChanged: (bool value) async {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
respectRules: value,
|
|
);
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class DnsModeItem extends StatelessWidget {
|
|
const DnsModeItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<ClashConfig, DnsMode>(
|
|
selector: (_, clashConfig) => clashConfig.dns.enhancedMode,
|
|
builder: (_, 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;
|
|
}
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(enhancedMode: value);
|
|
},
|
|
textBuilder: (dnsMode) => dnsMode.name,
|
|
value: enhancedMode,
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class FakeIpRangeItem extends StatelessWidget {
|
|
const FakeIpRangeItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<ClashConfig, String>(
|
|
selector: (_, clashConfig) => clashConfig.dns.fakeIpRange,
|
|
builder: (_, fakeIpRange, __) {
|
|
return ListItem.input(
|
|
title: Text(appLocalizations.fakeipRange),
|
|
subtitle: Text(fakeIpRange),
|
|
delegate: InputDelegate(
|
|
title: appLocalizations.fakeipRange,
|
|
value: fakeIpRange,
|
|
onChanged: (String? value) {
|
|
if (value != null) {
|
|
try {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
clashConfig.dns = clashConfig.dns.copyWith(
|
|
fakeIpRange: value,
|
|
);
|
|
} catch (e) {
|
|
globalState.showMessage(
|
|
title: appLocalizations.fakeipRange,
|
|
message: TextSpan(
|
|
text: e.toString(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class FakeIpFilterItem extends StatelessWidget {
|
|
const FakeIpFilterItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
title: Text(appLocalizations.fakeipFilter),
|
|
delegate: OpenDelegate(
|
|
isBlur: false,
|
|
title: appLocalizations.fakeipFilter,
|
|
widget: Selector<ClashConfig, List<String>>(
|
|
selector: (_, clashConfig) => clashConfig.dns.fakeIpFilter,
|
|
shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next),
|
|
builder: (_, fakeIpFilter, __) {
|
|
return ListPage(
|
|
title: appLocalizations.fakeipFilter,
|
|
items: fakeIpFilter,
|
|
titleBuilder: (item) => Text(item),
|
|
onChange: (items) {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
fakeIpFilter: List.from(items),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
extendPageWidth: 360,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class DefaultNameserverItem extends StatelessWidget {
|
|
const DefaultNameserverItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
title: Text(appLocalizations.defaultNameserver),
|
|
subtitle: Text(appLocalizations.defaultNameserverDesc),
|
|
delegate: OpenDelegate(
|
|
isBlur: false,
|
|
title: appLocalizations.defaultNameserver,
|
|
widget: Selector<ClashConfig, List<String>>(
|
|
selector: (_, clashConfig) => clashConfig.dns.defaultNameserver,
|
|
shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next),
|
|
builder: (_, defaultNameserver, __) {
|
|
return ListPage(
|
|
title: appLocalizations.defaultNameserver,
|
|
items: defaultNameserver,
|
|
titleBuilder: (item) => Text(item),
|
|
onChange: (items) {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
defaultNameserver: List.from(items),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
extendPageWidth: 360,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class NameserverItem extends StatelessWidget {
|
|
const NameserverItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
title: Text(appLocalizations.nameserver),
|
|
subtitle: Text(appLocalizations.nameserverDesc),
|
|
delegate: OpenDelegate(
|
|
title: appLocalizations.nameserver,
|
|
isBlur: false,
|
|
widget: Selector<ClashConfig, List<String>>(
|
|
selector: (_, clashConfig) => clashConfig.dns.nameserver,
|
|
shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next),
|
|
builder: (_, nameserver, __) {
|
|
return ListPage(
|
|
title: "域名服务器",
|
|
items: nameserver,
|
|
titleBuilder: (item) => Text(item),
|
|
onChange: (items) {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
nameserver: List.from(items),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
extendPageWidth: 360,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class UseHostsItem extends StatelessWidget {
|
|
const UseHostsItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<ClashConfig, bool>(
|
|
selector: (_, clashConfig) => clashConfig.dns.useHosts,
|
|
builder: (_, useHosts, __) {
|
|
return ListItem.switchItem(
|
|
title: Text(appLocalizations.useHosts),
|
|
delegate: SwitchDelegate(
|
|
value: useHosts,
|
|
onChanged: (bool value) async {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
useHosts: value,
|
|
);
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class UseSystemHostsItem extends StatelessWidget {
|
|
const UseSystemHostsItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<ClashConfig, bool>(
|
|
selector: (_, clashConfig) => clashConfig.dns.useSystemHosts,
|
|
builder: (_, useSystemHosts, __) {
|
|
return ListItem.switchItem(
|
|
title: Text(appLocalizations.useSystemHosts),
|
|
delegate: SwitchDelegate(
|
|
value: useSystemHosts,
|
|
onChanged: (bool value) async {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
useSystemHosts: value,
|
|
);
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class NameserverPolicyItem extends StatelessWidget {
|
|
const NameserverPolicyItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
title: Text(appLocalizations.nameserverPolicy),
|
|
subtitle: Text(appLocalizations.nameserverPolicyDesc),
|
|
delegate: OpenDelegate(
|
|
isBlur: false,
|
|
title: appLocalizations.nameserverPolicy,
|
|
widget: Selector<ClashConfig, Map<String, String>>(
|
|
selector: (_, clashConfig) => clashConfig.dns.nameserverPolicy,
|
|
shouldRebuild: (prev, next) =>
|
|
!const MapEquality<String, String>().equals(prev, next),
|
|
builder: (_, nameserverPolicy, __) {
|
|
return ListPage(
|
|
title: appLocalizations.nameserverPolicy,
|
|
items: nameserverPolicy.entries,
|
|
titleBuilder: (item) => Text(item.key),
|
|
subtitleBuilder: (item) => Text(item.value),
|
|
onChange: (items) {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
nameserverPolicy: Map.fromEntries(items),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
extendPageWidth: 360,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class ProxyServerNameserverItem extends StatelessWidget {
|
|
const ProxyServerNameserverItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
title: Text(appLocalizations.proxyNameserver),
|
|
subtitle: Text(appLocalizations.proxyNameserverDesc),
|
|
delegate: OpenDelegate(
|
|
isBlur: false,
|
|
title: appLocalizations.proxyNameserver,
|
|
widget: Selector<ClashConfig, List<String>>(
|
|
selector: (_, clashConfig) => clashConfig.dns.proxyServerNameserver,
|
|
shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next),
|
|
builder: (_, proxyServerNameserver, __) {
|
|
return ListPage(
|
|
title: appLocalizations.proxyNameserver,
|
|
items: proxyServerNameserver,
|
|
titleBuilder: (item) => Text(item),
|
|
onChange: (items) {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
proxyServerNameserver: List.from(items),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
extendPageWidth: 360,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class FallbackItem extends StatelessWidget {
|
|
const FallbackItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
title: Text(appLocalizations.fallback),
|
|
subtitle: Text(appLocalizations.fallbackDesc),
|
|
delegate: OpenDelegate(
|
|
isBlur: false,
|
|
title: appLocalizations.fallback,
|
|
widget: Selector<ClashConfig, List<String>>(
|
|
selector: (_, clashConfig) => clashConfig.dns.fallback,
|
|
shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next),
|
|
builder: (_, fallback, __) {
|
|
return ListPage(
|
|
title: appLocalizations.fallback,
|
|
items: fallback,
|
|
titleBuilder: (item) => Text(item),
|
|
onChange: (items) {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
fallback: List.from(items),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
extendPageWidth: 360,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class GeoipItem extends StatelessWidget {
|
|
const GeoipItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<ClashConfig, bool>(
|
|
selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.geoip,
|
|
builder: (_, geoip, __) {
|
|
return ListItem.switchItem(
|
|
title: const Text("Geoip"),
|
|
delegate: SwitchDelegate(
|
|
value: geoip,
|
|
onChanged: (bool value) async {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
fallbackFilter: dns.fallbackFilter.copyWith(geoip: value),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class GeoipCodeItem extends StatelessWidget {
|
|
const GeoipCodeItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Selector<ClashConfig, String>(
|
|
selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.geoipCode,
|
|
builder: (_, geoipCode, __) {
|
|
return ListItem.input(
|
|
title: Text(appLocalizations.geoipCode),
|
|
subtitle: Text(geoipCode),
|
|
delegate: InputDelegate(
|
|
title: appLocalizations.geoipCode,
|
|
value: geoipCode,
|
|
onChanged: (String? value) {
|
|
if (value != null) {
|
|
try {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
fallbackFilter: dns.fallbackFilter.copyWith(
|
|
geoipCode: value,
|
|
),
|
|
);
|
|
} catch (e) {
|
|
globalState.showMessage(
|
|
title: appLocalizations.geoipCode,
|
|
message: TextSpan(
|
|
text: e.toString(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class GeositeItem extends StatelessWidget {
|
|
const GeositeItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
title: const Text("Geosite"),
|
|
delegate: OpenDelegate(
|
|
isBlur: false,
|
|
title: "Geosite",
|
|
widget: Selector<ClashConfig, List<String>>(
|
|
selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.geosite,
|
|
shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next),
|
|
builder: (_, geosite, __) {
|
|
return ListPage(
|
|
title: "Geosite",
|
|
items: geosite,
|
|
titleBuilder: (item) => Text(item),
|
|
onChange: (items) {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
fallbackFilter: dns.fallbackFilter.copyWith(
|
|
geosite: List.from(items),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
extendPageWidth: 360,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class IpcidrItem extends StatelessWidget {
|
|
const IpcidrItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
title: Text(appLocalizations.ipcidr),
|
|
delegate: OpenDelegate(
|
|
isBlur: false,
|
|
title: appLocalizations.ipcidr,
|
|
widget: Selector<ClashConfig, List<String>>(
|
|
selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.ipcidr,
|
|
shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next),
|
|
builder: (_, ipcidr, __) {
|
|
return ListPage(
|
|
title: appLocalizations.ipcidr,
|
|
items: ipcidr,
|
|
titleBuilder: (item) => Text(item),
|
|
onChange: (items) {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
fallbackFilter: dns.fallbackFilter.copyWith(
|
|
ipcidr: List.from(items),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
extendPageWidth: 360,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class DomainItem extends StatelessWidget {
|
|
const DomainItem({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListItem.open(
|
|
title: Text(appLocalizations.domain),
|
|
delegate: OpenDelegate(
|
|
isBlur: false,
|
|
title: appLocalizations.domain,
|
|
widget: Selector<ClashConfig, List<String>>(
|
|
selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.domain,
|
|
shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next),
|
|
builder: (_, domain, __) {
|
|
return ListPage(
|
|
title: appLocalizations.domain,
|
|
items: domain,
|
|
titleBuilder: (item) => Text(item),
|
|
onChange: (items) {
|
|
final clashConfig = globalState.appController.clashConfig;
|
|
final dns = clashConfig.dns;
|
|
clashConfig.dns = dns.copyWith(
|
|
fallbackFilter: dns.fallbackFilter.copyWith(
|
|
domain: List.from(items),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
extendPageWidth: 360,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class DnsOptions extends StatelessWidget {
|
|
const DnsOptions({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
children: generateSection(
|
|
title: appLocalizations.options,
|
|
items: [
|
|
const StatusItem(),
|
|
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 StatelessWidget {
|
|
const DnsListView({super.key});
|
|
|
|
_initActions(BuildContext context) {
|
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
|
context.commonScaffoldState?.actions = [
|
|
IconButton(
|
|
onPressed: () async {
|
|
final res = await globalState.showMessage(
|
|
title: appLocalizations.reset,
|
|
message: TextSpan(
|
|
text: appLocalizations.resetTip,
|
|
),
|
|
);
|
|
if (res != true) {
|
|
return;
|
|
}
|
|
globalState.appController.clashConfig.dns = defaultDns;
|
|
},
|
|
tooltip: appLocalizations.reset,
|
|
icon: const Icon(
|
|
Icons.replay,
|
|
),
|
|
)
|
|
];
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
_initActions(context);
|
|
return generateListView(
|
|
dnsItems,
|
|
);
|
|
}
|
|
}
|