Add about page
This commit is contained in:
@@ -104,6 +104,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"about": {
|
||||||
|
"pageTitle": "about",
|
||||||
|
"version": "version",
|
||||||
|
"whatsNew": "what's new",
|
||||||
|
"sourceCode": "source code",
|
||||||
|
"telegramChannel": "telegram channel",
|
||||||
|
"checkForUpdate": "check for update"
|
||||||
|
},
|
||||||
"tray": {
|
"tray": {
|
||||||
"dashboard": "dashboard",
|
"dashboard": "dashboard",
|
||||||
"quit": "quit",
|
"quit": "quit",
|
||||||
|
|||||||
@@ -104,6 +104,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"about": {
|
||||||
|
"pageTitle": "درباره",
|
||||||
|
"version": "ورژن",
|
||||||
|
"whatsNew": "تغییرات",
|
||||||
|
"sourceCode": "سورس کد",
|
||||||
|
"telegramChannel": "کانال تلگرام",
|
||||||
|
"checkForUpdate": "بررسی آپدیت جدید"
|
||||||
|
},
|
||||||
"tray": {
|
"tray": {
|
||||||
"dashboard": "داشبورد",
|
"dashboard": "داشبورد",
|
||||||
"quit": "خروج",
|
"quit": "خروج",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ int getCurrentIndex(BuildContext context) {
|
|||||||
if (location.startsWith(ProxiesRoute.path)) return 1;
|
if (location.startsWith(ProxiesRoute.path)) return 1;
|
||||||
if (location.startsWith(LogsRoute.path)) return 2;
|
if (location.startsWith(LogsRoute.path)) return 2;
|
||||||
if (location.startsWith(SettingsRoute.path)) return 3;
|
if (location.startsWith(SettingsRoute.path)) return 3;
|
||||||
|
if (location.startsWith(AboutRoute.path)) return 4;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,5 +53,7 @@ void switchTab(int index, BuildContext context) {
|
|||||||
const LogsRoute().go(context);
|
const LogsRoute().go(context);
|
||||||
case 3:
|
case 3:
|
||||||
const SettingsRoute().go(context);
|
const SettingsRoute().go(context);
|
||||||
|
case 4:
|
||||||
|
const AboutRoute().go(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hiddify/core/router/routes/shared_routes.dart';
|
import 'package:hiddify/core/router/routes/shared_routes.dart';
|
||||||
|
import 'package:hiddify/features/about/view/view.dart';
|
||||||
import 'package:hiddify/features/logs/view/view.dart';
|
import 'package:hiddify/features/logs/view/view.dart';
|
||||||
import 'package:hiddify/features/settings/view/view.dart';
|
import 'package:hiddify/features/settings/view/view.dart';
|
||||||
import 'package:hiddify/features/wrapper/wrapper.dart';
|
import 'package:hiddify/features/wrapper/wrapper.dart';
|
||||||
@@ -20,6 +21,7 @@ part 'desktop_routes.g.dart';
|
|||||||
TypedGoRoute<ProxiesRoute>(path: ProxiesRoute.path),
|
TypedGoRoute<ProxiesRoute>(path: ProxiesRoute.path),
|
||||||
TypedGoRoute<LogsRoute>(path: LogsRoute.path),
|
TypedGoRoute<LogsRoute>(path: LogsRoute.path),
|
||||||
TypedGoRoute<SettingsRoute>(path: SettingsRoute.path),
|
TypedGoRoute<SettingsRoute>(path: SettingsRoute.path),
|
||||||
|
TypedGoRoute<AboutRoute>(path: AboutRoute.path),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
class DesktopWrapperRoute extends ShellRouteData {
|
class DesktopWrapperRoute extends ShellRouteData {
|
||||||
@@ -50,3 +52,13 @@ class SettingsRoute extends GoRouteData {
|
|||||||
return const NoTransitionPage(child: SettingsPage());
|
return const NoTransitionPage(child: SettingsPage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AboutRoute extends GoRouteData {
|
||||||
|
const AboutRoute();
|
||||||
|
static const path = '/about';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Page<void> buildPage(BuildContext context, GoRouterState state) {
|
||||||
|
return const NoTransitionPage(child: AboutPage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hiddify/core/router/routes/shared_routes.dart';
|
import 'package:hiddify/core/router/routes/shared_routes.dart';
|
||||||
|
import 'package:hiddify/features/about/view/view.dart';
|
||||||
import 'package:hiddify/features/logs/view/view.dart';
|
import 'package:hiddify/features/logs/view/view.dart';
|
||||||
import 'package:hiddify/features/settings/view/view.dart';
|
import 'package:hiddify/features/settings/view/view.dart';
|
||||||
import 'package:hiddify/features/wrapper/wrapper.dart';
|
import 'package:hiddify/features/wrapper/wrapper.dart';
|
||||||
@@ -60,3 +61,19 @@ class SettingsRoute extends GoRouteData {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TypedGoRoute<AboutRoute>(path: AboutRoute.path)
|
||||||
|
class AboutRoute extends GoRouteData {
|
||||||
|
const AboutRoute();
|
||||||
|
static const path = '/about';
|
||||||
|
|
||||||
|
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Page<void> buildPage(BuildContext context, GoRouterState state) {
|
||||||
|
return const MaterialPage(
|
||||||
|
fullscreenDialog: true,
|
||||||
|
child: AboutPage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,4 +4,6 @@ abstract class Constants {
|
|||||||
static const delayTestUrl = "https://www.google.com";
|
static const delayTestUrl = "https://www.google.com";
|
||||||
static const configFileName = "config";
|
static const configFileName = "config";
|
||||||
static const countryMMDBFileName = "Country";
|
static const countryMMDBFileName = "Country";
|
||||||
|
static const githubUrl = "https://github.com/hiddify/hiddify-next";
|
||||||
|
static const telegramChannelUrl = "https://t.me/hiddify";
|
||||||
}
|
}
|
||||||
|
|||||||
91
lib/features/about/view/about_page.dart
Normal file
91
lib/features/about/view/about_page.dart
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:gap/gap.dart';
|
||||||
|
import 'package:hiddify/core/core_providers.dart';
|
||||||
|
import 'package:hiddify/domain/constants.dart';
|
||||||
|
import 'package:hiddify/features/common/runtime_details.dart';
|
||||||
|
import 'package:hiddify/gen/assets.gen.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:recase/recase.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class AboutPage extends HookConsumerWidget {
|
||||||
|
const AboutPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final t = ref.watch(translationsProvider);
|
||||||
|
final details = ref.watch(runtimeDetailsNotifierProvider);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
body: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverAppBar(
|
||||||
|
title: Text(t.about.pageTitle.titleCase),
|
||||||
|
),
|
||||||
|
...switch (details) {
|
||||||
|
AsyncData(:final value) => [
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Assets.images.logo.svg(width: 64, height: 64),
|
||||||
|
const Gap(16),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
t.general.appTitle.titleCase,
|
||||||
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
|
),
|
||||||
|
const Gap(4),
|
||||||
|
Text(
|
||||||
|
"${t.about.version} ${value.version} ${value.buildNumber}",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverList(
|
||||||
|
delegate: SliverChildListDelegate(
|
||||||
|
[
|
||||||
|
ListTile(
|
||||||
|
title: Text(t.about.whatsNew.sentenceCase),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(t.about.sourceCode.sentenceCase),
|
||||||
|
trailing: const Icon(Icons.open_in_new),
|
||||||
|
onTap: () async {
|
||||||
|
await launchUrl(
|
||||||
|
Uri.parse(Constants.githubUrl),
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(t.about.telegramChannel.sentenceCase),
|
||||||
|
trailing: const Icon(Icons.open_in_new),
|
||||||
|
onTap: () async {
|
||||||
|
await launchUrl(
|
||||||
|
Uri.parse(Constants.telegramChannelUrl),
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(t.about.checkForUpdate.sentenceCase),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
_ => [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
lib/features/about/view/view.dart
Normal file
1
lib/features/about/view/view.dart
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export 'about_page.dart';
|
||||||
37
lib/features/common/runtime_details.dart
Normal file
37
lib/features/common/runtime_details.dart
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:hiddify/utils/utils.dart';
|
||||||
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'runtime_details.freezed.dart';
|
||||||
|
part 'runtime_details.g.dart';
|
||||||
|
|
||||||
|
// TODO implement clash version
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class RuntimeDetailsNotifier extends _$RuntimeDetailsNotifier with AppLogger {
|
||||||
|
@override
|
||||||
|
Future<RuntimeDetails> build() async {
|
||||||
|
final packageInfo = await PackageInfo.fromPlatform();
|
||||||
|
return RuntimeDetails(
|
||||||
|
version: packageInfo.version,
|
||||||
|
buildNumber: packageInfo.buildNumber,
|
||||||
|
installerStore: packageInfo.installerStore,
|
||||||
|
clashVersion: "",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class RuntimeDetails with _$RuntimeDetails {
|
||||||
|
const RuntimeDetails._();
|
||||||
|
|
||||||
|
const factory RuntimeDetails({
|
||||||
|
required String version,
|
||||||
|
required String buildNumber,
|
||||||
|
String? installerStore,
|
||||||
|
required String clashVersion,
|
||||||
|
}) = _RuntimeDetails;
|
||||||
|
|
||||||
|
factory RuntimeDetails.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$RuntimeDetailsFromJson(json);
|
||||||
|
}
|
||||||
@@ -33,6 +33,10 @@ class DesktopWrapper extends HookConsumerWidget {
|
|||||||
icon: const Icon(Icons.settings),
|
icon: const Icon(Icons.settings),
|
||||||
label: Text(t.settings.pageTitle.titleCase),
|
label: Text(t.settings.pageTitle.titleCase),
|
||||||
),
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: const Icon(Icons.info),
|
||||||
|
label: Text(t.about.pageTitle.titleCase),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|||||||
@@ -42,6 +42,12 @@ class MobileWrapper extends HookConsumerWidget {
|
|||||||
selected: location == LogsRoute.path,
|
selected: location == LogsRoute.path,
|
||||||
onSelect: () => const LogsRoute().push(context),
|
onSelect: () => const LogsRoute().push(context),
|
||||||
),
|
),
|
||||||
|
DrawerTile(
|
||||||
|
label: t.about.pageTitle.titleCase,
|
||||||
|
icon: Icons.info,
|
||||||
|
selected: location == AboutRoute.path,
|
||||||
|
onSelect: () => const AboutRoute().push(context),
|
||||||
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Align(
|
Align(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import Foundation
|
|||||||
|
|
||||||
import flutter_local_notifications
|
import flutter_local_notifications
|
||||||
import mobile_scanner
|
import mobile_scanner
|
||||||
|
import package_info_plus
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import protocol_handler
|
import protocol_handler
|
||||||
import proxy_manager
|
import proxy_manager
|
||||||
@@ -15,11 +16,13 @@ import share_plus
|
|||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
import sqlite3_flutter_libs
|
import sqlite3_flutter_libs
|
||||||
import tray_manager
|
import tray_manager
|
||||||
|
import url_launcher_macos
|
||||||
import window_manager
|
import window_manager
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||||
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
|
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
|
||||||
|
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
ProtocolHandlerPlugin.register(with: registry.registrar(forPlugin: "ProtocolHandlerPlugin"))
|
ProtocolHandlerPlugin.register(with: registry.registrar(forPlugin: "ProtocolHandlerPlugin"))
|
||||||
ProxyManagerPlugin.register(with: registry.registrar(forPlugin: "ProxyManagerPlugin"))
|
ProxyManagerPlugin.register(with: registry.registrar(forPlugin: "ProxyManagerPlugin"))
|
||||||
@@ -28,5 +31,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
||||||
TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin"))
|
TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin"))
|
||||||
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
||||||
}
|
}
|
||||||
|
|||||||
56
pubspec.lock
56
pubspec.lock
@@ -645,6 +645,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.3"
|
version: "0.15.3"
|
||||||
|
http:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http
|
||||||
|
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
http_multi_server:
|
http_multi_server:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -805,6 +813,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
package_info_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: package_info_plus
|
||||||
|
sha256: ceb027f6bc6a60674a233b4a90a7658af1aebdea833da0b5b53c1e9821a78c7b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.2"
|
||||||
|
package_info_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_info_plus_platform_interface
|
||||||
|
sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
path:
|
path:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1330,6 +1354,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.2.2"
|
||||||
|
url_launcher:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: url_launcher
|
||||||
|
sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.12"
|
||||||
|
url_launcher_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_android
|
||||||
|
sha256: "78cb6dea3e93148615109e58e42c35d1ffbf5ef66c44add673d0ab75f12ff3af"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.37"
|
||||||
|
url_launcher_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_ios
|
||||||
|
sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.4"
|
||||||
url_launcher_linux:
|
url_launcher_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1338,6 +1386,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.5"
|
version: "3.0.5"
|
||||||
|
url_launcher_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_macos
|
||||||
|
sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.6"
|
||||||
url_launcher_platform_interface:
|
url_launcher_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ dependencies:
|
|||||||
share_plus: ^7.0.2
|
share_plus: ^7.0.2
|
||||||
window_manager: ^0.3.5
|
window_manager: ^0.3.5
|
||||||
tray_manager: ^0.2.0
|
tray_manager: ^0.2.0
|
||||||
|
package_info_plus: ^4.0.2
|
||||||
|
|
||||||
# utils
|
# utils
|
||||||
combine: ^0.5.3
|
combine: ^0.5.3
|
||||||
@@ -76,6 +77,7 @@ dependencies:
|
|||||||
sliver_tools: ^0.2.12
|
sliver_tools: ^0.2.12
|
||||||
flutter_adaptive_scaffold: ^0.1.6
|
flutter_adaptive_scaffold: ^0.1.6
|
||||||
fl_chart: ^0.63.0
|
fl_chart: ^0.63.0
|
||||||
|
url_launcher: ^6.1.12
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user