Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f679d1e6d8 |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,26 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="240"
|
||||
android:viewportHeight="240"
|
||||
android:tint="#FFFFFF">
|
||||
<group android:scaleX="2.0264318"
|
||||
android:scaleY="2.0264318"
|
||||
android:translateX="-123.17181"
|
||||
android:translateY="-123.17181">
|
||||
<group android:scaleX="0.61"
|
||||
android:scaleY="0.61"
|
||||
android:translateX="46.8"
|
||||
android:translateY="46.8">
|
||||
<path
|
||||
android:pathData="M67.67,115.76L144.04,39.39A18,18 0,0 1,169.5 39.39L169.5,39.39A18,18 0,0 1,169.5 64.85L93.13,141.21A18,18 0,0 1,67.67 141.21L67.67,141.21A18,18 0,0 1,67.67 115.76z"
|
||||
android:fillColor="#6666FF"/>
|
||||
<path
|
||||
android:pathData="M98.79,146.87L136.97,108.69A18,18 72.93,0 1,162.43 108.69L162.43,108.69A18,18 72.93,0 1,162.43 134.14L124.24,172.33A18,18 76.87,0 1,98.79 172.33L98.79,172.33A18,18 76.87,0 1,98.79 146.87z"
|
||||
android:fillColor="#326CBF"/>
|
||||
<path
|
||||
android:pathData="M129.9,177.98L129.9,177.98A18,18 107.07,0 1,155.36 177.98L155.36,177.98A18,18 107.07,0 1,155.36 203.44L155.36,203.44A18,18 107.07,0 1,129.9 203.44L129.9,203.44A18,18 107.07,0 1,129.9 177.98z"
|
||||
android:fillColor="#56afee"/>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
|
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 532 B |
|
Before Width: | Height: | Size: 423 B After Width: | Height: | Size: 311 B |
|
Before Width: | Height: | Size: 803 B After Width: | Height: | Size: 671 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 932 B |
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -3,23 +3,23 @@
|
||||
android:height="108dp"
|
||||
android:viewportWidth="240"
|
||||
android:viewportHeight="240">
|
||||
<group android:scaleX="0.924"
|
||||
android:scaleY="0.924"
|
||||
android:translateX="9.12"
|
||||
android:translateY="9.12">
|
||||
<group android:scaleX="0.63461536"
|
||||
android:scaleY="0.63461536"
|
||||
android:translateX="45.96154"
|
||||
android:translateY="43.846153">
|
||||
<group android:scaleX="0.90244895"
|
||||
android:scaleY="0.90244895"
|
||||
android:translateX="12.708843"
|
||||
android:translateY="10.703402">
|
||||
<group android:scaleX="0.61"
|
||||
android:scaleY="0.61"
|
||||
android:translateX="46.8"
|
||||
android:translateY="46.8">
|
||||
<path
|
||||
android:pathData="M60.65,89.6L154.18,35.6A18,18 107.59,0 1,178.77 42.19L178.77,42.19A18,18 107.59,0 1,172.18 66.78L78.65,120.78A18,18 106.67,0 1,54.06 114.19L54.06,114.19A18,18 106.67,0 1,60.65 89.6z"
|
||||
android:fillColor="#6666FB"/>
|
||||
android:pathData="M67.67,115.76L144.04,39.39A18,18 0,0 1,169.5 39.39L169.5,39.39A18,18 0,0 1,169.5 64.85L93.13,141.21A18,18 0,0 1,67.67 141.21L67.67,141.21A18,18 0,0 1,67.67 115.76z"
|
||||
android:fillColor="#6666FF"/>
|
||||
<path
|
||||
android:pathData="M84.65,131.17L131.42,104.17A18,18 107.83,0 1,156 110.76L156,110.76A18,18 107.83,0 1,149.42 135.35L102.65,162.35A18,18 106.67,0 1,78.06 155.76L78.06,155.76A18,18 106.67,0 1,84.65 131.17z"
|
||||
android:fillColor="#336AB6"/>
|
||||
android:pathData="M98.79,146.87L136.97,108.69A18,18 72.93,0 1,162.43 108.69L162.43,108.69A18,18 72.93,0 1,162.43 134.14L124.24,172.33A18,18 76.87,0 1,98.79 172.33L98.79,172.33A18,18 76.87,0 1,98.79 146.87z"
|
||||
android:fillColor="#326CBF"/>
|
||||
<path
|
||||
android:pathData="M108.65,172.74L108.65,172.74A18,18 116.03,0 1,133.24 179.33L133.24,179.33A18,18 116.03,0 1,126.65 203.92L126.65,203.92A18,18 116.03,0 1,102.06 197.33L102.06,197.33A18,18 116.03,0 1,108.65 172.74z"
|
||||
android:fillColor="#5CA8E9"/>
|
||||
android:pathData="M129.9,177.98L129.9,177.98A18,18 107.07,0 1,155.36 177.98L155.36,177.98A18,18 107.07,0 1,155.36 203.44L155.36,203.44A18,18 107.07,0 1,129.9 203.44L129.9,203.44A18,18 107.07,0 1,129.9 177.98z"
|
||||
android:fillColor="#56afee"/>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 886 B After Width: | Height: | Size: 812 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
BIN
assets/images/app_icon.ico
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 7.0 KiB |
BIN
assets/images/launch_icon.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
@@ -101,9 +101,9 @@ class Other {
|
||||
|
||||
String getTrayIconPath() {
|
||||
if (Platform.isWindows) {
|
||||
return "assets/images/icon.ico";
|
||||
return "assets/images/app_icon.ico";
|
||||
} else {
|
||||
return "assets/images/icon_monochrome.png";
|
||||
return "assets/images/launch_icon.png";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,16 @@
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:fl_clash/widgets/list.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
@immutable
|
||||
class Contributor {
|
||||
final String avatar;
|
||||
final String name;
|
||||
final String link;
|
||||
|
||||
const Contributor({
|
||||
required this.avatar,
|
||||
required this.name,
|
||||
required this.link,
|
||||
});
|
||||
}
|
||||
|
||||
class AboutFragment extends StatelessWidget {
|
||||
const AboutFragment({super.key});
|
||||
|
||||
_checkUpdate(BuildContext context) async {
|
||||
final commonScaffoldState = context.commonScaffoldState;
|
||||
if (commonScaffoldState?.mounted != true) return;
|
||||
final data = await commonScaffoldState?.loadingRun<Map<String, dynamic>?>(
|
||||
final data =
|
||||
await commonScaffoldState?.loadingRun<Map<String, dynamic>?>(
|
||||
request.checkForUpdate,
|
||||
title: appLocalizations.checkUpdate,
|
||||
);
|
||||
@@ -33,40 +20,84 @@ class AboutFragment extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildMoreSection(BuildContext context) {
|
||||
return generateSection(
|
||||
separated: false,
|
||||
title: appLocalizations.more,
|
||||
items: [
|
||||
ListItem(
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView(
|
||||
padding: kMaterialListPadding.copyWith(
|
||||
top: 16,
|
||||
bottom: 16,
|
||||
),
|
||||
children: [
|
||||
ListTile(
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: 16,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/launch_icon.png',
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
appName,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
Text(
|
||||
globalState.packageInfo.version,
|
||||
style: Theme.of(context).textTheme.labelLarge,
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
appLocalizations.desc,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
ListTile(
|
||||
title: Text(appLocalizations.checkUpdate),
|
||||
onTap: () {
|
||||
_checkUpdate(context);
|
||||
},
|
||||
),
|
||||
ListItem(
|
||||
ListTile(
|
||||
title: const Text("Telegram"),
|
||||
onTap: () {
|
||||
globalState.openUrl(
|
||||
"https://t.me/+G-veVtwBOl4wODc1",
|
||||
launchUrl(
|
||||
Uri.parse("https://t.me/+G-veVtwBOl4wODc1"),
|
||||
);
|
||||
},
|
||||
trailing: const Icon(Icons.launch),
|
||||
),
|
||||
ListItem(
|
||||
ListTile(
|
||||
title: Text(appLocalizations.project),
|
||||
onTap: () {
|
||||
globalState.openUrl(
|
||||
"https://github.com/$repository",
|
||||
launchUrl(
|
||||
Uri.parse("https://github.com/$repository"),
|
||||
);
|
||||
},
|
||||
trailing: const Icon(Icons.launch),
|
||||
),
|
||||
ListItem(
|
||||
ListTile(
|
||||
title: Text(appLocalizations.core),
|
||||
onTap: () {
|
||||
globalState.openUrl(
|
||||
"https://github.com/chen08209/Clash.Meta/tree/FlClash",
|
||||
launchUrl(
|
||||
Uri.parse("https://github.com/chen08209/Clash.Meta/tree/FlClash"),
|
||||
);
|
||||
},
|
||||
trailing: const Icon(Icons.launch),
|
||||
@@ -74,139 +105,4 @@ class AboutFragment extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildContributorsSection() {
|
||||
const contributors = [
|
||||
Contributor(
|
||||
avatar: "assets/images/avatars/june2.jpg",
|
||||
name: "June2",
|
||||
link: "https://t.me/Jibadong",
|
||||
),
|
||||
Contributor(
|
||||
avatar: "assets/images/avatars/arue.jpg",
|
||||
name: "Arue",
|
||||
link: "https://t.me/xrcm6868",
|
||||
),
|
||||
];
|
||||
return generateSection(
|
||||
separated: false,
|
||||
title: appLocalizations.contributors,
|
||||
items: [
|
||||
ListItem(
|
||||
title: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Wrap(
|
||||
spacing: 24,
|
||||
children: [
|
||||
for (final contributor in contributors)
|
||||
Avatar(
|
||||
contributor: contributor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final items = [
|
||||
ListTile(
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: 16,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Image.asset(
|
||||
'assets/images/icon.png',
|
||||
width: 64,
|
||||
height: 64,
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
appName,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
Text(
|
||||
globalState.packageInfo.version,
|
||||
style: Theme.of(context).textTheme.labelLarge,
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
appLocalizations.desc,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
..._buildContributorsSection(),
|
||||
..._buildMoreSection(context),
|
||||
];
|
||||
return Padding(
|
||||
padding: kMaterialListPadding.copyWith(
|
||||
top: 16,
|
||||
bottom: 16,
|
||||
),
|
||||
child: generateListView(items),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Avatar extends StatelessWidget {
|
||||
final Contributor contributor;
|
||||
|
||||
const Avatar({
|
||||
super.key,
|
||||
required this.contributor,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
hoverColor: Colors.transparent,
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 36,
|
||||
height: 36,
|
||||
child: CircleAvatar(
|
||||
foregroundImage: AssetImage(
|
||||
contributor.avatar,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
contributor.name,
|
||||
style: context.textTheme.bodySmall,
|
||||
)
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
globalState.openUrl(contributor.link);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,8 @@ class _BackupAndRecoveryState extends State<BackupAndRecovery> {
|
||||
return Center(
|
||||
child: FadeBox(
|
||||
key: const Key("fade_box_1"),
|
||||
child: snapshot.connectionState == ConnectionState.waiting
|
||||
child: snapshot.connectionState ==
|
||||
ConnectionState.waiting
|
||||
? const SizedBox(
|
||||
width: 12,
|
||||
height: 12,
|
||||
@@ -158,12 +159,12 @@ class _BackupAndRecoveryState extends State<BackupAndRecovery> {
|
||||
ListHeader(
|
||||
title: appLocalizations.backupAndRecovery),
|
||||
ListItem(
|
||||
onTap: _backup,
|
||||
onTab: _backup,
|
||||
title: Text(appLocalizations.backup),
|
||||
subtitle: Text(appLocalizations.backupDesc),
|
||||
),
|
||||
ListItem(
|
||||
onTap: _handleRecovery,
|
||||
onTab: _handleRecovery,
|
||||
title: Text(appLocalizations.recovery),
|
||||
subtitle: Text(appLocalizations.recoveryDesc),
|
||||
),
|
||||
@@ -340,13 +341,13 @@ class _RecoveryOptionsDialogState extends State<RecoveryOptionsDialog> {
|
||||
child: Wrap(
|
||||
children: [
|
||||
ListItem(
|
||||
onTap: () {
|
||||
onTab: () {
|
||||
_handleOnTab(RecoveryOption.onlyProfiles);
|
||||
},
|
||||
title: Text(appLocalizations.recoveryProfiles),
|
||||
),
|
||||
ListItem(
|
||||
onTap: () {
|
||||
onTab: () {
|
||||
_handleOnTab(RecoveryOption.all);
|
||||
},
|
||||
title: Text(appLocalizations.recoveryAll),
|
||||
|
||||
@@ -210,7 +210,7 @@ class _ConfigFragmentState extends State<ConfigFragment> {
|
||||
leading: const Icon(Icons.info_outline),
|
||||
title: Text(appLocalizations.logLevel),
|
||||
subtitle: Text(value.name),
|
||||
onTap: () {
|
||||
onTab: () {
|
||||
_showLogLevelDialog(value);
|
||||
},
|
||||
);
|
||||
@@ -223,7 +223,7 @@ class _ConfigFragmentState extends State<ConfigFragment> {
|
||||
leading: const Icon(Icons.computer_outlined),
|
||||
title: const Text("UA"),
|
||||
subtitle: Text(value ?? appLocalizations.defaultText),
|
||||
onTap: () {
|
||||
onTab: () {
|
||||
_showUaDialog(value);
|
||||
},
|
||||
);
|
||||
@@ -236,7 +236,7 @@ class _ConfigFragmentState extends State<ConfigFragment> {
|
||||
leading: const Icon(Icons.timeline),
|
||||
title: Text(appLocalizations.testUrl),
|
||||
subtitle: Text(value),
|
||||
onTap: () {
|
||||
onTab: () {
|
||||
_modifyTestUrl(value);
|
||||
},
|
||||
);
|
||||
@@ -246,7 +246,7 @@ class _ConfigFragmentState extends State<ConfigFragment> {
|
||||
selector: (_, clashConfig) => clashConfig.mixedPort,
|
||||
builder: (_, mixedPort, __) {
|
||||
return ListItem(
|
||||
onTap: () {
|
||||
onTab: () {
|
||||
_modifyMixedPort(mixedPort);
|
||||
},
|
||||
leading: const Icon(Icons.adjust_outlined),
|
||||
|
||||
@@ -48,19 +48,19 @@ class AddProfile extends StatelessWidget {
|
||||
leading: const Icon(Icons.qr_code),
|
||||
title: Text(appLocalizations.qrcode),
|
||||
subtitle: Text(appLocalizations.qrcodeDesc),
|
||||
onTap: _toScan,
|
||||
onTab: _toScan,
|
||||
),
|
||||
ListItem(
|
||||
leading: const Icon(Icons.upload_file),
|
||||
title: Text(appLocalizations.file),
|
||||
subtitle: Text(appLocalizations.fileDesc),
|
||||
onTap: _handleAddProfileFormFile,
|
||||
onTab: _handleAddProfileFormFile,
|
||||
),
|
||||
ListItem(
|
||||
leading: const Icon(Icons.cloud_download),
|
||||
title: Text(appLocalizations.url),
|
||||
subtitle: Text(appLocalizations.urlDesc),
|
||||
onTap: _toAdd,
|
||||
onTab: _toAdd,
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
0
lib/fragments/proxies.dart
Normal file
@@ -211,8 +211,5 @@
|
||||
"sort": "Sort",
|
||||
"columns": "Columns",
|
||||
"proxiesSetting": "Proxies setting",
|
||||
"proxyGroup": "Proxy group",
|
||||
"go": "Go",
|
||||
"externalLink": "External link",
|
||||
"contributors": "Contributors"
|
||||
"proxyGroup": "Proxy group"
|
||||
}
|
||||
@@ -211,8 +211,5 @@
|
||||
"sort": "排序",
|
||||
"columns": "列数",
|
||||
"proxiesSetting": "代理设置",
|
||||
"proxyGroup": "代理组",
|
||||
"go": "前往",
|
||||
"externalLink": "外部链接",
|
||||
"contributors": "贡献者"
|
||||
"proxyGroup": "代理组"
|
||||
}
|
||||
@@ -97,7 +97,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"connectionsDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"View current connections data"),
|
||||
"connectivity": MessageLookupByLibrary.simpleMessage("Connectivity:"),
|
||||
"contributors": MessageLookupByLibrary.simpleMessage("Contributors"),
|
||||
"copy": MessageLookupByLibrary.simpleMessage("Copy"),
|
||||
"core": MessageLookupByLibrary.simpleMessage("Core"),
|
||||
"coreInfo": MessageLookupByLibrary.simpleMessage("Core info"),
|
||||
@@ -136,7 +135,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
MessageLookupByLibrary.simpleMessage("ExternalController"),
|
||||
"externalControllerDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Once enabled, the Clash kernel can be controlled on port 9090"),
|
||||
"externalLink": MessageLookupByLibrary.simpleMessage("External link"),
|
||||
"externalResources":
|
||||
MessageLookupByLibrary.simpleMessage("External resources"),
|
||||
"file": MessageLookupByLibrary.simpleMessage("File"),
|
||||
@@ -155,7 +153,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"geodataLoaderDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Enabling will use the Geo low memory loader"),
|
||||
"global": MessageLookupByLibrary.simpleMessage("Global"),
|
||||
"go": MessageLookupByLibrary.simpleMessage("Go"),
|
||||
"goDownload": MessageLookupByLibrary.simpleMessage("Go to download"),
|
||||
"hours": MessageLookupByLibrary.simpleMessage("Hours"),
|
||||
"importFromURL":
|
||||
|
||||
@@ -79,7 +79,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"connections": MessageLookupByLibrary.simpleMessage("连接"),
|
||||
"connectionsDesc": MessageLookupByLibrary.simpleMessage("查看当前连接数据"),
|
||||
"connectivity": MessageLookupByLibrary.simpleMessage("连通性:"),
|
||||
"contributors": MessageLookupByLibrary.simpleMessage("贡献者"),
|
||||
"copy": MessageLookupByLibrary.simpleMessage("复制"),
|
||||
"core": MessageLookupByLibrary.simpleMessage("内核"),
|
||||
"coreInfo": MessageLookupByLibrary.simpleMessage("内核信息"),
|
||||
@@ -112,7 +111,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"externalController": MessageLookupByLibrary.simpleMessage("外部控制器"),
|
||||
"externalControllerDesc":
|
||||
MessageLookupByLibrary.simpleMessage("开启后将可以通过9090端口控制Clash内核"),
|
||||
"externalLink": MessageLookupByLibrary.simpleMessage("外部链接"),
|
||||
"externalResources": MessageLookupByLibrary.simpleMessage("外部资源"),
|
||||
"file": MessageLookupByLibrary.simpleMessage("文件"),
|
||||
"fileDesc": MessageLookupByLibrary.simpleMessage("直接上传配置文件"),
|
||||
@@ -127,7 +125,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"geodataLoaderDesc":
|
||||
MessageLookupByLibrary.simpleMessage("开启将使用Geo低内存加载器"),
|
||||
"global": MessageLookupByLibrary.simpleMessage("全局"),
|
||||
"go": MessageLookupByLibrary.simpleMessage("前往"),
|
||||
"goDownload": MessageLookupByLibrary.simpleMessage("前往下载"),
|
||||
"hours": MessageLookupByLibrary.simpleMessage("小时"),
|
||||
"importFromURL": MessageLookupByLibrary.simpleMessage("从URL导入"),
|
||||
|
||||
@@ -2179,36 +2179,6 @@ class AppLocalizations {
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Go`
|
||||
String get go {
|
||||
return Intl.message(
|
||||
'Go',
|
||||
name: 'go',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `External link`
|
||||
String get externalLink {
|
||||
return Intl.message(
|
||||
'External link',
|
||||
name: 'externalLink',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Contributors`
|
||||
String get contributors {
|
||||
return Intl.message(
|
||||
'Contributors',
|
||||
name: 'contributors',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||
|
||||
@@ -13,20 +13,6 @@ typedef OnSelected = void Function(int index);
|
||||
class HomePage extends StatelessWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
_navigationBarContainer({
|
||||
required BuildContext context,
|
||||
required Widget child,
|
||||
}) {
|
||||
// if (!system.isDesktop) return child;
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16).copyWith(
|
||||
right: 0,
|
||||
),
|
||||
color: context.colorScheme.surface,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
_getNavigationBar({
|
||||
required BuildContext context,
|
||||
required ViewMode viewMode,
|
||||
@@ -48,48 +34,56 @@ class HomePage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
final extended = viewMode == ViewMode.desktop;
|
||||
return _navigationBarContainer(
|
||||
context: context,
|
||||
child: NavigationRail(
|
||||
groupAlignment: -0.8,
|
||||
destinations: navigationItems
|
||||
.map(
|
||||
(e) => NavigationRailDestination(
|
||||
icon: e.icon,
|
||||
label: Text(
|
||||
Intl.message(e.label),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onDestinationSelected: globalState.appController.toPage,
|
||||
extended: extended,
|
||||
minExtendedWidth: 172,
|
||||
selectedIndex: currentIndex,
|
||||
labelType: extended
|
||||
? NavigationRailLabelType.none
|
||||
: NavigationRailLabelType.selected,
|
||||
// return NavigationRail(
|
||||
// backgroundColor: context.colorScheme.surfaceContainer,
|
||||
// groupAlignment: -0.8,
|
||||
// destinations: navigationItems
|
||||
// .map(
|
||||
// (e) => NavigationRailDestination(
|
||||
// icon: e.icon,
|
||||
// label: Text(
|
||||
// Intl.message(e.label),
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// .toList(),
|
||||
// onDestinationSelected: globalState.appController.toPage,
|
||||
// extended: extended,
|
||||
// minExtendedWidth: 172,
|
||||
// selectedIndex: currentIndex,
|
||||
// labelType: extended
|
||||
// ? NavigationRailLabelType.none
|
||||
// : NavigationRailLabelType.selected,
|
||||
// );
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16).copyWith(
|
||||
right: 0,
|
||||
),
|
||||
color: context.colorScheme.surface,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: NavigationRail(
|
||||
backgroundColor: context.colorScheme.surfaceContainer,
|
||||
groupAlignment: -0.8,
|
||||
destinations: navigationItems
|
||||
.map(
|
||||
(e) => NavigationRailDestination(
|
||||
icon: e.icon,
|
||||
label: Text(
|
||||
Intl.message(e.label),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onDestinationSelected: globalState.appController.toPage,
|
||||
extended: extended,
|
||||
minExtendedWidth: 172,
|
||||
selectedIndex: currentIndex,
|
||||
labelType: extended
|
||||
? NavigationRailLabelType.none
|
||||
: NavigationRailLabelType.selected,
|
||||
),
|
||||
),
|
||||
);
|
||||
return NavigationRail(
|
||||
groupAlignment: -0.95,
|
||||
destinations: navigationItems
|
||||
.map(
|
||||
(e) => NavigationRailDestination(
|
||||
icon: e.icon,
|
||||
label: Text(
|
||||
Intl.message(e.label),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onDestinationSelected: globalState.appController.toPage,
|
||||
extended: extended,
|
||||
minExtendedWidth: 172,
|
||||
selectedIndex: currentIndex,
|
||||
labelType: extended
|
||||
? NavigationRailLabelType.none
|
||||
: NavigationRailLabelType.selected,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -116,7 +110,7 @@ class HomePage extends StatelessWidget {
|
||||
final navigationItems = state.navigationItems;
|
||||
final currentLabel = state.currentLabel;
|
||||
final index = navigationItems.lastIndexWhere(
|
||||
(element) => element.label == currentLabel,
|
||||
(element) => element.label == currentLabel,
|
||||
);
|
||||
final currentIndex = index == -1 ? 0 : index;
|
||||
final navigationBar = _getNavigationBar(
|
||||
@@ -126,9 +120,9 @@ class HomePage extends StatelessWidget {
|
||||
currentIndex: currentIndex,
|
||||
);
|
||||
final bottomNavigationBar =
|
||||
viewMode == ViewMode.mobile ? navigationBar : null;
|
||||
viewMode == ViewMode.mobile ? navigationBar : null;
|
||||
final sideNavigationBar =
|
||||
viewMode != ViewMode.mobile ? navigationBar : null;
|
||||
viewMode != ViewMode.mobile ? navigationBar : null;
|
||||
return CommonScaffold(
|
||||
key: globalState.homeScaffoldKey,
|
||||
title: Intl.message(
|
||||
|
||||
@@ -7,7 +7,6 @@ import 'package:fl_clash/plugins/proxy.dart';
|
||||
import 'package:fl_clash/widgets/scaffold.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import 'controller.dart';
|
||||
|
||||
@@ -124,7 +123,7 @@ class GlobalState {
|
||||
}) async {
|
||||
appState.isInit = clashCore.isInit;
|
||||
if (!appState.isInit) {
|
||||
if (Platform.isAndroid) {
|
||||
if(Platform.isAndroid){
|
||||
clashCore.setProps(
|
||||
Props(
|
||||
accessControl: config.isAccessControl ? config.accessControl : null,
|
||||
@@ -262,17 +261,6 @@ class GlobalState {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
openUrl(String url) {
|
||||
showMessage(
|
||||
message: TextSpan(text: url),
|
||||
title: appLocalizations.externalLink,
|
||||
confirmText: appLocalizations.go,
|
||||
onTab: () {
|
||||
launchUrl(Uri.parse(url));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final globalState = GlobalState();
|
||||
|
||||
@@ -78,7 +78,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
final Widget? trailing;
|
||||
final Delegate delegate;
|
||||
final double? horizontalTitleGap;
|
||||
final void Function()? onTap;
|
||||
final void Function()? onTab;
|
||||
|
||||
const ListItem({
|
||||
super.key,
|
||||
@@ -89,7 +89,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
this.trailing,
|
||||
this.horizontalTitleGap,
|
||||
this.prue,
|
||||
this.onTap,
|
||||
this.onTab,
|
||||
this.tileTitleAlignment = ListTileTitleAlignment.center,
|
||||
}) : delegate = const Delegate();
|
||||
|
||||
@@ -104,7 +104,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
this.horizontalTitleGap,
|
||||
this.prue,
|
||||
this.tileTitleAlignment = ListTileTitleAlignment.center,
|
||||
}) : onTap = null;
|
||||
}) : onTab = null;
|
||||
|
||||
const ListItem.next({
|
||||
super.key,
|
||||
@@ -117,7 +117,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
this.horizontalTitleGap,
|
||||
this.prue,
|
||||
this.tileTitleAlignment = ListTileTitleAlignment.center,
|
||||
}) : onTap = null;
|
||||
}) : onTab = null;
|
||||
|
||||
const ListItem.checkbox({
|
||||
super.key,
|
||||
@@ -130,7 +130,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
this.prue,
|
||||
this.tileTitleAlignment = ListTileTitleAlignment.center,
|
||||
}) : trailing = null,
|
||||
onTap = null;
|
||||
onTab = null;
|
||||
|
||||
const ListItem.switchItem({
|
||||
super.key,
|
||||
@@ -143,7 +143,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
this.prue,
|
||||
this.tileTitleAlignment = ListTileTitleAlignment.center,
|
||||
}) : trailing = null,
|
||||
onTap = null;
|
||||
onTab = null;
|
||||
|
||||
const ListItem.radio({
|
||||
super.key,
|
||||
@@ -156,10 +156,10 @@ class ListItem<T> extends StatelessWidget {
|
||||
this.prue,
|
||||
this.tileTitleAlignment = ListTileTitleAlignment.center,
|
||||
}) : leading = null,
|
||||
onTap = null;
|
||||
onTab = null;
|
||||
|
||||
_buildListTile({
|
||||
void Function()? onTap,
|
||||
void Function()? onTab,
|
||||
Widget? trailing,
|
||||
Widget? leading,
|
||||
}) {
|
||||
@@ -188,7 +188,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
}
|
||||
return InkWell(
|
||||
splashFactory: NoSplash.splashFactory,
|
||||
onTap: onTap,
|
||||
onTap: onTab,
|
||||
child: Container(
|
||||
padding: padding,
|
||||
child: Row(
|
||||
@@ -203,7 +203,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
titleAlignment: tileTitleAlignment,
|
||||
onTap: onTap,
|
||||
onTap: onTab,
|
||||
trailing: trailing ?? this.trailing,
|
||||
contentPadding: padding,
|
||||
);
|
||||
@@ -230,7 +230,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
action();
|
||||
}
|
||||
|
||||
return _buildListTile(onTap: openAction);
|
||||
return _buildListTile(onTab: openAction);
|
||||
},
|
||||
openBuilder: (_, action) {
|
||||
return CommonScaffold.open(
|
||||
@@ -245,7 +245,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
if (delegate is NextDelegate) {
|
||||
final nextDelegate = delegate as NextDelegate;
|
||||
return _buildListTile(
|
||||
onTap: () {
|
||||
onTab: () {
|
||||
final isMobile =
|
||||
globalState.appController.appState.viewMode == ViewMode.mobile;
|
||||
if (!isMobile) {
|
||||
@@ -272,7 +272,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
if (delegate is CheckboxDelegate) {
|
||||
final checkboxDelegate = delegate as CheckboxDelegate;
|
||||
return _buildListTile(
|
||||
onTap: () {
|
||||
onTab: () {
|
||||
if (checkboxDelegate.onChanged != null) {
|
||||
checkboxDelegate.onChanged!(!checkboxDelegate.value);
|
||||
}
|
||||
@@ -286,7 +286,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
if (delegate is SwitchDelegate) {
|
||||
final switchDelegate = delegate as SwitchDelegate;
|
||||
return _buildListTile(
|
||||
onTap: () {
|
||||
onTab: () {
|
||||
if (switchDelegate.onChanged != null) {
|
||||
switchDelegate.onChanged!(!switchDelegate.value);
|
||||
}
|
||||
@@ -300,7 +300,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
if (delegate is RadioDelegate) {
|
||||
final radioDelegate = delegate as RadioDelegate<T>;
|
||||
return _buildListTile(
|
||||
onTap: () {
|
||||
onTab: () {
|
||||
if (radioDelegate.onChanged != null) {
|
||||
radioDelegate.onChanged!(radioDelegate.value);
|
||||
}
|
||||
@@ -319,7 +319,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
}
|
||||
|
||||
return _buildListTile(
|
||||
onTap: onTap,
|
||||
onTab: onTab,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,20 +28,39 @@ showExtendPage(
|
||||
builder: (_, viewWidth, __) {
|
||||
final isMobile =
|
||||
globalState.appController.appState.viewMode == ViewMode.mobile;
|
||||
final commonScaffold = CommonScaffold(
|
||||
automaticallyImplyLeading: isMobile ? true : false,
|
||||
actions: isMobile
|
||||
? null
|
||||
: [
|
||||
const SizedBox(
|
||||
height: kToolbarHeight,
|
||||
width: kToolbarHeight,
|
||||
child: CloseButton(),
|
||||
final commonScaffold = isMobile
|
||||
? CommonScaffold(
|
||||
actions: isMobile
|
||||
? null
|
||||
: [
|
||||
const SizedBox(
|
||||
height: kToolbarHeight,
|
||||
width: kToolbarHeight,
|
||||
child: CloseButton(),
|
||||
),
|
||||
],
|
||||
title: title,
|
||||
body: uniqueBody,
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
title: Text(title),
|
||||
actions: const [
|
||||
SizedBox(
|
||||
height: kToolbarHeight,
|
||||
width: kToolbarHeight,
|
||||
child: CloseButton(),
|
||||
)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: uniqueBody,
|
||||
),
|
||||
],
|
||||
title: title,
|
||||
body: uniqueBody,
|
||||
);
|
||||
);
|
||||
return AnimatedContainer(
|
||||
duration: kThemeAnimationDuration,
|
||||
width: isMobile ? viewWidth : extendPageWidth ?? 300,
|
||||
|
||||
@@ -594,7 +594,6 @@ Future<T?> showModalSideSheet<T>({
|
||||
AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
title: Text(title),
|
||||
centerTitle: false,
|
||||
actions: const [
|
||||
SizedBox(
|
||||
height: kToolbarHeight,
|
||||
|
||||
@@ -207,6 +207,7 @@ class _WindowHeaderState extends State<WindowHeader> {
|
||||
children: [
|
||||
Positioned(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onPanStart: (_) {
|
||||
windowManager.startDragging();
|
||||
},
|
||||
@@ -214,7 +215,7 @@ class _WindowHeaderState extends State<WindowHeader> {
|
||||
_updateMaximized();
|
||||
},
|
||||
child: Container(
|
||||
color: context.colorScheme.surface,
|
||||
color: context.colorScheme.surfaceContainerHigh,
|
||||
alignment: Alignment.centerLeft,
|
||||
height: kHeaderHeight,
|
||||
),
|
||||
@@ -246,10 +247,10 @@ class AppIcon extends StatelessWidget {
|
||||
child: const Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
width: 28,
|
||||
height: 28,
|
||||
child: CircleAvatar(
|
||||
foregroundImage: AssetImage("assets/images/icon.png"),
|
||||
foregroundImage: AssetImage("assets/images/launch_icon.png"),
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
display_name: FlClash
|
||||
|
||||
icon: ./assets/images/icon.png
|
||||
icon: ./assets/images/launch_icon.png
|
||||
|
||||
keywords:
|
||||
- FlClash
|
||||
|
||||
@@ -8,7 +8,7 @@ priority: optional
|
||||
section: x11
|
||||
installed_size: 6604
|
||||
essential: false
|
||||
icon: ./assets/images/icon.png
|
||||
icon: ./assets/images/launch_icon.png
|
||||
|
||||
|
||||
keywords:
|
||||
|
||||
@@ -8,7 +8,7 @@ priority: optional
|
||||
section: x11
|
||||
installed_size: 6604
|
||||
essential: false
|
||||
icon: ./assets/images/icon.png
|
||||
icon: ./assets/images/launch_icon.png
|
||||
|
||||
keywords:
|
||||
- FlClash
|
||||
|
||||
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 222 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 645 B |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 3.6 KiB |
@@ -1,7 +1,7 @@
|
||||
name: fl_clash
|
||||
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
|
||||
publish_to: 'none'
|
||||
version: 0.8.47+202407222
|
||||
version: 0.8.45+202407201
|
||||
environment:
|
||||
sdk: '>=3.1.0 <4.0.0'
|
||||
|
||||
@@ -58,7 +58,6 @@ flutter:
|
||||
assets:
|
||||
- assets/data/
|
||||
- assets/images/
|
||||
- assets/images/avatars/
|
||||
ffigen:
|
||||
name: "ClashFFI"
|
||||
output: 'lib/clash/generated/clash_ffi.dart'
|
||||
|
||||
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.4 KiB |