diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png index dcedc44a..76687bbe 100644 Binary files a/android/app/src/main/ic_launcher-playstore.png and b/android/app/src/main/ic_launcher-playstore.png differ diff --git a/android/app/src/main/res/drawable-anydpi-v24/ic_stat_name.xml b/android/app/src/main/res/drawable-anydpi-v24/ic_stat_name.xml deleted file mode 100644 index b341caf4..00000000 --- a/android/app/src/main/res/drawable-anydpi-v24/ic_stat_name.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - diff --git a/android/app/src/main/res/drawable-hdpi/ic_stat_name.png b/android/app/src/main/res/drawable-hdpi/ic_stat_name.png index f4ac6c64..188d2752 100644 Binary files a/android/app/src/main/res/drawable-hdpi/ic_stat_name.png and b/android/app/src/main/res/drawable-hdpi/ic_stat_name.png differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_stat_name.png b/android/app/src/main/res/drawable-mdpi/ic_stat_name.png index 61efe332..9e22a161 100644 Binary files a/android/app/src/main/res/drawable-mdpi/ic_stat_name.png and b/android/app/src/main/res/drawable-mdpi/ic_stat_name.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/ic_stat_name.png b/android/app/src/main/res/drawable-xhdpi/ic_stat_name.png index 08077fd2..a0e0795f 100644 Binary files a/android/app/src/main/res/drawable-xhdpi/ic_stat_name.png and b/android/app/src/main/res/drawable-xhdpi/ic_stat_name.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png b/android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png index 70cecb6c..320b7498 100644 Binary files a/android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png and b/android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png b/android/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png new file mode 100644 index 00000000..24834c27 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png differ diff --git a/android/app/src/main/res/drawable/ic_launcher_foreground.xml b/android/app/src/main/res/drawable/ic_launcher_foreground.xml index e57794c8..1ee1f3ae 100644 --- a/android/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/android/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -3,23 +3,23 @@ android:height="108dp" android:viewportWidth="240" android:viewportHeight="240"> - - + + + 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="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="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"/> diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp index 064e864d..1165d3ef 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp index 49c42a29..595b977d 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp index f41a9c62..7c410c3f 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp index 92abe540..0665b801 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp index cadc8114..1893e21f 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp index f0009608..415ae4fd 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp index c2e97a2f..a43cd437 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp index e043fa5b..4f0a8e69 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp index befaabda..10a4b060 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp index 522d4c9b..3e0ddc0d 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/assets/images/app_icon.ico b/assets/images/app_icon.ico deleted file mode 100644 index 3c59a7bb..00000000 Binary files a/assets/images/app_icon.ico and /dev/null differ diff --git a/assets/images/avatars/arue.jpg b/assets/images/avatars/arue.jpg new file mode 100644 index 00000000..76c10659 Binary files /dev/null and b/assets/images/avatars/arue.jpg differ diff --git a/assets/images/avatars/june2.jpg b/assets/images/avatars/june2.jpg new file mode 100644 index 00000000..3005ff0a Binary files /dev/null and b/assets/images/avatars/june2.jpg differ diff --git a/assets/images/icon.ico b/assets/images/icon.ico new file mode 100644 index 00000000..a19b33c5 Binary files /dev/null and b/assets/images/icon.ico differ diff --git a/assets/images/icon.png b/assets/images/icon.png new file mode 100644 index 00000000..32c8fe12 Binary files /dev/null and b/assets/images/icon.png differ diff --git a/assets/images/icon_monochrome.png b/assets/images/icon_monochrome.png new file mode 100644 index 00000000..9fe8eb14 Binary files /dev/null and b/assets/images/icon_monochrome.png differ diff --git a/assets/images/launch_icon.png b/assets/images/launch_icon.png deleted file mode 100644 index 86b78b63..00000000 Binary files a/assets/images/launch_icon.png and /dev/null differ diff --git a/lib/common/other.dart b/lib/common/other.dart index 536b2490..8f2ff76f 100644 --- a/lib/common/other.dart +++ b/lib/common/other.dart @@ -101,9 +101,9 @@ class Other { String getTrayIconPath() { if (Platform.isWindows) { - return "assets/images/app_icon.ico"; + return "assets/images/icon.ico"; } else { - return "assets/images/launch_icon.png"; + return "assets/images/icon_monochrome.png"; } } diff --git a/lib/fragments/about.dart b/lib/fragments/about.dart index 5e16d2ae..611594b7 100644 --- a/lib/fragments/about.dart +++ b/lib/fragments/about.dart @@ -1,16 +1,29 @@ 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?>( + final data = await commonScaffoldState?.loadingRun?>( request.checkForUpdate, title: appLocalizations.checkUpdate, ); @@ -20,84 +33,40 @@ class AboutFragment extends StatelessWidget { ); } - @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( + List _buildMoreSection(BuildContext context) { + return generateSection( + separated: false, + title: appLocalizations.more, + items: [ + ListItem( title: Text(appLocalizations.checkUpdate), onTap: () { _checkUpdate(context); }, ), - ListTile( + ListItem( title: const Text("Telegram"), onTap: () { - launchUrl( - Uri.parse("https://t.me/+G-veVtwBOl4wODc1"), + globalState.openUrl( + "https://t.me/+G-veVtwBOl4wODc1", ); }, trailing: const Icon(Icons.launch), ), - ListTile( + ListItem( title: Text(appLocalizations.project), onTap: () { - launchUrl( - Uri.parse("https://github.com/$repository"), + globalState.openUrl( + "https://github.com/$repository", ); }, trailing: const Icon(Icons.launch), ), - ListTile( + ListItem( title: Text(appLocalizations.core), onTap: () { - launchUrl( - Uri.parse("https://github.com/chen08209/Clash.Meta/tree/FlClash"), + globalState.openUrl( + "https://github.com/chen08209/Clash.Meta/tree/FlClash", ); }, trailing: const Icon(Icons.launch), @@ -105,4 +74,139 @@ class AboutFragment extends StatelessWidget { ], ); } + + List _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); + }, + ); + } } diff --git a/lib/fragments/backup_and_recovery.dart b/lib/fragments/backup_and_recovery.dart index ca02637e..2d306881 100644 --- a/lib/fragments/backup_and_recovery.dart +++ b/lib/fragments/backup_and_recovery.dart @@ -113,8 +113,7 @@ class _BackupAndRecoveryState extends State { 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, @@ -159,12 +158,12 @@ class _BackupAndRecoveryState extends State { ListHeader( title: appLocalizations.backupAndRecovery), ListItem( - onTab: _backup, + onTap: _backup, title: Text(appLocalizations.backup), subtitle: Text(appLocalizations.backupDesc), ), ListItem( - onTab: _handleRecovery, + onTap: _handleRecovery, title: Text(appLocalizations.recovery), subtitle: Text(appLocalizations.recoveryDesc), ), @@ -341,13 +340,13 @@ class _RecoveryOptionsDialogState extends State { child: Wrap( children: [ ListItem( - onTab: () { + onTap: () { _handleOnTab(RecoveryOption.onlyProfiles); }, title: Text(appLocalizations.recoveryProfiles), ), ListItem( - onTab: () { + onTap: () { _handleOnTab(RecoveryOption.all); }, title: Text(appLocalizations.recoveryAll), diff --git a/lib/fragments/config.dart b/lib/fragments/config.dart index a3dab7ba..d5f903bc 100644 --- a/lib/fragments/config.dart +++ b/lib/fragments/config.dart @@ -210,7 +210,7 @@ class _ConfigFragmentState extends State { leading: const Icon(Icons.info_outline), title: Text(appLocalizations.logLevel), subtitle: Text(value.name), - onTab: () { + onTap: () { _showLogLevelDialog(value); }, ); @@ -223,7 +223,7 @@ class _ConfigFragmentState extends State { leading: const Icon(Icons.computer_outlined), title: const Text("UA"), subtitle: Text(value ?? appLocalizations.defaultText), - onTab: () { + onTap: () { _showUaDialog(value); }, ); @@ -236,7 +236,7 @@ class _ConfigFragmentState extends State { leading: const Icon(Icons.timeline), title: Text(appLocalizations.testUrl), subtitle: Text(value), - onTab: () { + onTap: () { _modifyTestUrl(value); }, ); @@ -246,7 +246,7 @@ class _ConfigFragmentState extends State { selector: (_, clashConfig) => clashConfig.mixedPort, builder: (_, mixedPort, __) { return ListItem( - onTab: () { + onTap: () { _modifyMixedPort(mixedPort); }, leading: const Icon(Icons.adjust_outlined), diff --git a/lib/fragments/profiles/add_profile.dart b/lib/fragments/profiles/add_profile.dart index 378612fc..4e93e9f4 100644 --- a/lib/fragments/profiles/add_profile.dart +++ b/lib/fragments/profiles/add_profile.dart @@ -48,19 +48,19 @@ class AddProfile extends StatelessWidget { leading: const Icon(Icons.qr_code), title: Text(appLocalizations.qrcode), subtitle: Text(appLocalizations.qrcodeDesc), - onTab: _toScan, + onTap: _toScan, ), ListItem( leading: const Icon(Icons.upload_file), title: Text(appLocalizations.file), subtitle: Text(appLocalizations.fileDesc), - onTab: _handleAddProfileFormFile, + onTap: _handleAddProfileFormFile, ), ListItem( leading: const Icon(Icons.cloud_download), title: Text(appLocalizations.url), subtitle: Text(appLocalizations.urlDesc), - onTab: _toAdd, + onTap: _toAdd, ) ], ); diff --git a/lib/fragments/proxies.dart b/lib/fragments/proxies.dart deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/l10n/arb/intl_en.arb b/lib/l10n/arb/intl_en.arb index 6b9acd90..6d6e1b7e 100644 --- a/lib/l10n/arb/intl_en.arb +++ b/lib/l10n/arb/intl_en.arb @@ -211,5 +211,8 @@ "sort": "Sort", "columns": "Columns", "proxiesSetting": "Proxies setting", - "proxyGroup": "Proxy group" + "proxyGroup": "Proxy group", + "go": "Go", + "externalLink": "External link", + "contributors": "Contributors" } \ No newline at end of file diff --git a/lib/l10n/arb/intl_zh_CN.arb b/lib/l10n/arb/intl_zh_CN.arb index a24bc87a..41c987bb 100644 --- a/lib/l10n/arb/intl_zh_CN.arb +++ b/lib/l10n/arb/intl_zh_CN.arb @@ -211,5 +211,8 @@ "sort": "排序", "columns": "列数", "proxiesSetting": "代理设置", - "proxyGroup": "代理组" + "proxyGroup": "代理组", + "go": "前往", + "externalLink": "外部链接", + "contributors": "贡献者" } \ No newline at end of file diff --git a/lib/l10n/intl/messages_en.dart b/lib/l10n/intl/messages_en.dart index d966643f..8c651348 100644 --- a/lib/l10n/intl/messages_en.dart +++ b/lib/l10n/intl/messages_en.dart @@ -97,6 +97,7 @@ 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"), @@ -135,6 +136,7 @@ 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"), @@ -153,6 +155,7 @@ 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": diff --git a/lib/l10n/intl/messages_zh_CN.dart b/lib/l10n/intl/messages_zh_CN.dart index 0fd7455b..63eb8137 100644 --- a/lib/l10n/intl/messages_zh_CN.dart +++ b/lib/l10n/intl/messages_zh_CN.dart @@ -79,6 +79,7 @@ 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("内核信息"), @@ -111,6 +112,7 @@ class MessageLookup extends MessageLookupByLibrary { "externalController": MessageLookupByLibrary.simpleMessage("外部控制器"), "externalControllerDesc": MessageLookupByLibrary.simpleMessage("开启后将可以通过9090端口控制Clash内核"), + "externalLink": MessageLookupByLibrary.simpleMessage("外部链接"), "externalResources": MessageLookupByLibrary.simpleMessage("外部资源"), "file": MessageLookupByLibrary.simpleMessage("文件"), "fileDesc": MessageLookupByLibrary.simpleMessage("直接上传配置文件"), @@ -125,6 +127,7 @@ class MessageLookup extends MessageLookupByLibrary { "geodataLoaderDesc": MessageLookupByLibrary.simpleMessage("开启将使用Geo低内存加载器"), "global": MessageLookupByLibrary.simpleMessage("全局"), + "go": MessageLookupByLibrary.simpleMessage("前往"), "goDownload": MessageLookupByLibrary.simpleMessage("前往下载"), "hours": MessageLookupByLibrary.simpleMessage("小时"), "importFromURL": MessageLookupByLibrary.simpleMessage("从URL导入"), diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index fce2d6ba..66eb0936 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -2179,6 +2179,36 @@ 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 { diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 0c96a4b4..0e658e3c 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -13,6 +13,20 @@ 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, @@ -34,57 +48,49 @@ class HomePage extends StatelessWidget { ); } final extended = viewMode == ViewMode.desktop; - // 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), - ), + 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, - ), + ), + ) + .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, + ); } @override @@ -110,7 +116,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( @@ -120,9 +126,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( diff --git a/lib/state.dart b/lib/state.dart index ba38b238..c77f5bfc 100644 --- a/lib/state.dart +++ b/lib/state.dart @@ -7,6 +7,7 @@ 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'; @@ -123,7 +124,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, @@ -261,6 +262,17 @@ 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(); diff --git a/lib/widgets/list.dart b/lib/widgets/list.dart index be9eb433..0dd2c3de 100644 --- a/lib/widgets/list.dart +++ b/lib/widgets/list.dart @@ -78,7 +78,7 @@ class ListItem extends StatelessWidget { final Widget? trailing; final Delegate delegate; final double? horizontalTitleGap; - final void Function()? onTab; + final void Function()? onTap; const ListItem({ super.key, @@ -89,7 +89,7 @@ class ListItem extends StatelessWidget { this.trailing, this.horizontalTitleGap, this.prue, - this.onTab, + this.onTap, this.tileTitleAlignment = ListTileTitleAlignment.center, }) : delegate = const Delegate(); @@ -104,7 +104,7 @@ class ListItem extends StatelessWidget { this.horizontalTitleGap, this.prue, this.tileTitleAlignment = ListTileTitleAlignment.center, - }) : onTab = null; + }) : onTap = null; const ListItem.next({ super.key, @@ -117,7 +117,7 @@ class ListItem extends StatelessWidget { this.horizontalTitleGap, this.prue, this.tileTitleAlignment = ListTileTitleAlignment.center, - }) : onTab = null; + }) : onTap = null; const ListItem.checkbox({ super.key, @@ -130,7 +130,7 @@ class ListItem extends StatelessWidget { this.prue, this.tileTitleAlignment = ListTileTitleAlignment.center, }) : trailing = null, - onTab = null; + onTap = null; const ListItem.switchItem({ super.key, @@ -143,7 +143,7 @@ class ListItem extends StatelessWidget { this.prue, this.tileTitleAlignment = ListTileTitleAlignment.center, }) : trailing = null, - onTab = null; + onTap = null; const ListItem.radio({ super.key, @@ -156,10 +156,10 @@ class ListItem extends StatelessWidget { this.prue, this.tileTitleAlignment = ListTileTitleAlignment.center, }) : leading = null, - onTab = null; + onTap = null; _buildListTile({ - void Function()? onTab, + void Function()? onTap, Widget? trailing, Widget? leading, }) { @@ -188,7 +188,7 @@ class ListItem extends StatelessWidget { } return InkWell( splashFactory: NoSplash.splashFactory, - onTap: onTab, + onTap: onTap, child: Container( padding: padding, child: Row( @@ -203,7 +203,7 @@ class ListItem extends StatelessWidget { title: title, subtitle: subtitle, titleAlignment: tileTitleAlignment, - onTap: onTab, + onTap: onTap, trailing: trailing ?? this.trailing, contentPadding: padding, ); @@ -230,7 +230,7 @@ class ListItem extends StatelessWidget { action(); } - return _buildListTile(onTab: openAction); + return _buildListTile(onTap: openAction); }, openBuilder: (_, action) { return CommonScaffold.open( @@ -245,7 +245,7 @@ class ListItem extends StatelessWidget { if (delegate is NextDelegate) { final nextDelegate = delegate as NextDelegate; return _buildListTile( - onTab: () { + onTap: () { final isMobile = globalState.appController.appState.viewMode == ViewMode.mobile; if (!isMobile) { @@ -272,7 +272,7 @@ class ListItem extends StatelessWidget { if (delegate is CheckboxDelegate) { final checkboxDelegate = delegate as CheckboxDelegate; return _buildListTile( - onTab: () { + onTap: () { if (checkboxDelegate.onChanged != null) { checkboxDelegate.onChanged!(!checkboxDelegate.value); } @@ -286,7 +286,7 @@ class ListItem extends StatelessWidget { if (delegate is SwitchDelegate) { final switchDelegate = delegate as SwitchDelegate; return _buildListTile( - onTab: () { + onTap: () { if (switchDelegate.onChanged != null) { switchDelegate.onChanged!(!switchDelegate.value); } @@ -300,7 +300,7 @@ class ListItem extends StatelessWidget { if (delegate is RadioDelegate) { final radioDelegate = delegate as RadioDelegate; return _buildListTile( - onTab: () { + onTap: () { if (radioDelegate.onChanged != null) { radioDelegate.onChanged!(radioDelegate.value); } @@ -319,7 +319,7 @@ class ListItem extends StatelessWidget { } return _buildListTile( - onTab: onTab, + onTap: onTap, ); } } diff --git a/lib/widgets/sheet.dart b/lib/widgets/sheet.dart index 323da2d7..dee4e520 100644 --- a/lib/widgets/sheet.dart +++ b/lib/widgets/sheet.dart @@ -28,39 +28,20 @@ showExtendPage( builder: (_, viewWidth, __) { final isMobile = globalState.appController.appState.viewMode == ViewMode.mobile; - 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, + final commonScaffold = CommonScaffold( + automaticallyImplyLeading: isMobile ? true : false, + actions: isMobile + ? null + : [ + const SizedBox( + height: kToolbarHeight, + width: kToolbarHeight, + child: CloseButton(), ), ], - ); + title: title, + body: uniqueBody, + ); return AnimatedContainer( duration: kThemeAnimationDuration, width: isMobile ? viewWidth : extendPageWidth ?? 300, diff --git a/lib/widgets/side_sheet.dart b/lib/widgets/side_sheet.dart index 8b792c23..d546f326 100644 --- a/lib/widgets/side_sheet.dart +++ b/lib/widgets/side_sheet.dart @@ -594,6 +594,7 @@ Future showModalSideSheet({ AppBar( automaticallyImplyLeading: false, title: Text(title), + centerTitle: false, actions: const [ SizedBox( height: kToolbarHeight, diff --git a/lib/widgets/window_container.dart b/lib/widgets/window_container.dart index 387ee581..09cdd118 100644 --- a/lib/widgets/window_container.dart +++ b/lib/widgets/window_container.dart @@ -207,7 +207,6 @@ class _WindowHeaderState extends State { children: [ Positioned( child: GestureDetector( - behavior: HitTestBehavior.translucent, onPanStart: (_) { windowManager.startDragging(); }, @@ -215,7 +214,7 @@ class _WindowHeaderState extends State { _updateMaximized(); }, child: Container( - color: context.colorScheme.surfaceContainerHigh, + color: context.colorScheme.surface, alignment: Alignment.centerLeft, height: kHeaderHeight, ), @@ -247,10 +246,10 @@ class AppIcon extends StatelessWidget { child: const Row( children: [ SizedBox( - width: 28, - height: 28, + width: 24, + height: 24, child: CircleAvatar( - foregroundImage: AssetImage("assets/images/launch_icon.png"), + foregroundImage: AssetImage("assets/images/icon.png"), backgroundColor: Colors.transparent, ), ), diff --git a/linux/packaging/appimage/make_config.yaml b/linux/packaging/appimage/make_config.yaml index 7014159a..6f44d7d3 100644 --- a/linux/packaging/appimage/make_config.yaml +++ b/linux/packaging/appimage/make_config.yaml @@ -1,6 +1,6 @@ display_name: FlClash -icon: ./assets/images/launch_icon.png +icon: ./assets/images/icon.png keywords: - FlClash diff --git a/linux/packaging/deb/make_config.yaml b/linux/packaging/deb/make_config.yaml index 36b69571..86879ee6 100644 --- a/linux/packaging/deb/make_config.yaml +++ b/linux/packaging/deb/make_config.yaml @@ -8,7 +8,7 @@ priority: optional section: x11 installed_size: 6604 essential: false -icon: ./assets/images/launch_icon.png +icon: ./assets/images/icon.png keywords: diff --git a/linux/packaging/rpm/make_config.yaml b/linux/packaging/rpm/make_config.yaml index 57ccc672..50a7ddab 100644 --- a/linux/packaging/rpm/make_config.yaml +++ b/linux/packaging/rpm/make_config.yaml @@ -8,7 +8,7 @@ priority: optional section: x11 installed_size: 6604 essential: false -icon: ./assets/images/launch_icon.png +icon: ./assets/images/icon.png keywords: - FlClash diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png index 256bf7ea..62f4fbcc 100755 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png index 1d85f13b..cffc437b 100755 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png index c862e32e..2c704b60 100755 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png index 04c55dde..c485cc67 100755 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png index 79cf4944..09fd5c53 100755 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png index 42c6d2cb..c4321229 100755 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png index 7a59386e..1502b9c5 100755 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/pubspec.yaml b/pubspec.yaml index cf29d584..98534cee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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.45+202407201 +version: 0.8.46+202407221 environment: sdk: '>=3.1.0 <4.0.0' @@ -58,6 +58,7 @@ flutter: assets: - assets/data/ - assets/images/ + - assets/images/avatars/ ffigen: name: "ClashFFI" output: 'lib/clash/generated/clash_ffi.dart' diff --git a/windows/packaging/exe/make_config.yaml b/windows/packaging/exe/make_config.yaml index 8d173565..b34de6e9 100644 --- a/windows/packaging/exe/make_config.yaml +++ b/windows/packaging/exe/make_config.yaml @@ -5,7 +5,7 @@ publisher_url: https://github.com/chen08209/FlClash display_name: FlClash executable_name: FlClash.exe output_base_file_name: FlClash.exe -setup_icon_file: ..\windows\runner\resources\app_icon.ico +setup_icon_file: ..\windows\runner\resources\icon.ico locales: - lang: zh file: ..\windows\packaging\exe\ChineseSimplified.isl diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico index 3c59a7bb..a19b33c5 100644 Binary files a/windows/runner/resources/app_icon.ico and b/windows/runner/resources/app_icon.ico differ