diff --git a/l10n_arb/intl_zh_CN.arb b/l10n_arb/intl_zh_CN.arb index 3f4ec49..f739d1e 100644 --- a/l10n_arb/intl_zh_CN.arb +++ b/l10n_arb/intl_zh_CN.arb @@ -23,6 +23,7 @@ "hide": "隐藏", "add": "添加", "requiredField": "必填", + "skipLoading": "跳过加载", "durationJustNow": "刚刚", "durationSeconds": "{number} 秒前", diff --git a/lib/l10n/intl/messages_zh-CN.dart b/lib/l10n/intl/messages_zh-CN.dart index 1f52771..fbe3f74 100644 --- a/lib/l10n/intl/messages_zh-CN.dart +++ b/lib/l10n/intl/messages_zh-CN.dart @@ -242,6 +242,7 @@ class MessageLookup extends MessageLookupByLibrary { "serverSetup": MessageLookupByLibrary.simpleMessage("服务器设置"), "settings": MessageLookupByLibrary.simpleMessage("设置"), "showServerConfig": MessageLookupByLibrary.simpleMessage("查看服务器信息"), + "skipLoading": MessageLookupByLibrary.simpleMessage("跳过加载"), "steamScanResultFinished": MessageLookupByLibrary.simpleMessage("扫描完成"), "steamScanResultLibraryEmpty": MessageLookupByLibrary.simpleMessage("Steam游戏库为空"), diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index b7346be..2034450 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -280,6 +280,16 @@ class S { ); } + /// `跳过加载` + String get skipLoading { + return Intl.message( + '跳过加载', + name: 'skipLoading', + desc: '', + args: [], + ); + } + /// `刚刚` String get durationJustNow { return Intl.message( diff --git a/lib/main_window.dart b/lib/main_window.dart index a80a53d..e44c04d 100644 --- a/lib/main_window.dart +++ b/lib/main_window.dart @@ -8,7 +8,6 @@ import 'package:go_router/go_router.dart'; import 'bloc/deeplink_bloc.dart'; import 'bloc/main_bloc.dart'; import 'common/platform.dart'; -import 'view/pages/server_select_overlay.dart'; import 'view/specialized/theme_mode_toggle.dart'; import 'view/specialized/title_bar.dart'; @@ -27,9 +26,7 @@ class MainWindow extends StatelessWidget { maintainBottomViewPadding: true, child: Stack( children: [ - ClipRect( - child: ServerSelectOverlay(child: child), - ), + child, const TitleBar( actions: [ThemeModeToggle()], ), diff --git a/lib/route.dart b/lib/route.dart index e0868a7..f198724 100644 --- a/lib/route.dart +++ b/lib/route.dart @@ -149,7 +149,7 @@ class InitRoute extends GoRouteData { const InitRoute(); @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) => + Page buildPage(BuildContext context, GoRouterState state) => NoTransitionPage( child: MainWindow( key: mainWindowKey, @@ -163,7 +163,7 @@ class WebLandingRoute extends GoRouteData { const WebLandingRoute(); @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) => + Page buildPage(BuildContext context, GoRouterState state) => NoTransitionPage( child: MainWindow( key: mainWindowKey, @@ -180,8 +180,7 @@ class ImageViewerRoute extends GoRouteData { final List? $extra; @override - CustomTransitionPage buildPage( - BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { return CustomTransitionPage( fullscreenDialog: true, opaque: false, @@ -236,7 +235,7 @@ class ModuleRoute extends StatefulShellRouteData { const ModuleRoute(); @override - NoTransitionPage pageBuilder( + Page pageBuilder( BuildContext context, GoRouterState state, StatefulNavigationShell navigationShell, @@ -275,7 +274,7 @@ class TipherethRootRoute extends GoRouteData { const TipherethRootRoute(); @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { context.read().add(TipherethGetAccountsEvent()); return const NoTransitionPage( child: ModuleFramePage( @@ -308,7 +307,7 @@ class YesodFunctionRoute extends GoRouteData { final dynamic $extra; @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { final yesodPages = { YesodFunctions.recent: const YesodRecentPage(), YesodFunctions.timeline: Container(), @@ -397,7 +396,7 @@ class GeburaStoreRoute extends GoRouteData { const GeburaStoreRoute(); @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { return NoTransitionPage( child: GeburaRoute.rootWidget( child: const ModuleFramePage( @@ -415,7 +414,7 @@ class GeburaLibraryRoute extends GoRouteData { const GeburaLibraryRoute(); @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { return NoTransitionPage( child: GeburaRoute.rootWidget( child: const ModuleFramePage( @@ -441,7 +440,7 @@ class GeburaLibrarySettingsRoute extends GoRouteData { final dynamic $extra; @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { final actions = { GeburaLibrarySettingsActions.commonAppScanResult: GeburaCommonAppScanResultPanel( @@ -475,7 +474,7 @@ class GeburaLibraryDetailRoute extends GoRouteData { final String uuid; @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { final actions = { GeburaLibraryDetailActions.assignApp: const GeburaAssignAppPanel(), }; @@ -504,7 +503,7 @@ class ChesedRootRoute extends GoRouteData { const ChesedRootRoute(); @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { context.read().add(ChesedSearchImagesEvent('')); return const NoTransitionPage( child: ModuleFramePage( @@ -525,7 +524,7 @@ class NotificationRootRoute extends GoRouteData { const NotificationRootRoute(); @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { context.read().add(NetzachSystemNotificationLoadEvent(1)); return const NoTransitionPage( child: ModuleFramePage( @@ -558,7 +557,7 @@ class SettingsFunctionRoute extends GoRouteData { final dynamic $extra; @override - NoTransitionPage buildPage(BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { final settingsPages = { SettingsFunctions.client: const ClientSettingPage(), SettingsFunctions.session: const SessionManagePage(), diff --git a/lib/view/pages/gebura/gebura_nav.dart b/lib/view/pages/gebura/gebura_nav.dart index 1d3f38d..d7b3a9c 100644 --- a/lib/view/pages/gebura/gebura_nav.dart +++ b/lib/view/pages/gebura/gebura_nav.dart @@ -9,6 +9,7 @@ import '../../../bloc/gebura/gebura_bloc.dart'; import '../../../l10n/l10n.dart'; import '../../../model/gebura_model.dart'; import '../../../route.dart'; +import '../../helper/connection.dart'; import '../../layout/overlapping_panels.dart'; import '../../universal/universal.dart'; import 'gebura_common.dart'; @@ -33,15 +34,16 @@ class GeburaNav extends StatelessWidget { builder: (context, state) { return Column( children: [ - UniversalListTile( - leading: Icon(UniversalUI.of(context).icons.shoppingCart), - onTap: () { - const GeburaStoreRoute().go(context); - OverlappingPanels.of(context)?.reveal(RevealSide.main); - }, - title: Text(S.of(context).store), - selected: function == GeburaFunctions.store, - ), + if (ConnectionHelper.isNotLocal(context)) + UniversalListTile( + leading: Icon(UniversalUI.of(context).icons.shoppingCart), + onTap: () { + const GeburaStoreRoute().go(context); + OverlappingPanels.of(context)?.reveal(RevealSide.main); + }, + title: Text(S.of(context).store), + selected: function == GeburaFunctions.store, + ), UniversalListTile( leading: Icon(UniversalUI.of(context).icons.apps), onTap: () { diff --git a/lib/view/pages/init_page.dart b/lib/view/pages/init_page.dart index 909aadb..873d0ad 100644 --- a/lib/view/pages/init_page.dart +++ b/lib/view/pages/init_page.dart @@ -9,7 +9,7 @@ import '../../l10n/l10n.dart'; import '../../route.dart'; import '../components/toast.dart'; import '../layout/bootstrap_container.dart'; -import '../universal/card.dart'; +import '../universal/universal.dart'; import 'server_select_overlay.dart'; class InitPage extends StatefulWidget { @@ -39,52 +39,35 @@ class _InitPageState extends State { const TipherethRootRoute().go(context); ServerSelectOverlay.of(context)?.minimize(); Toast(title: '', message: S.of(context).welcomeBack).show(context); + } else if (state is MainAutoLoginState && state.failed) { + if (PlatformHelper.isWeb() && + (DotEnvValue.andClientDownloadUrl.isNotEmpty || + DotEnvValue.winClientDownloadUrl.isNotEmpty)) { + ServerSelectOverlay.of(context)?.hide(); + const WebLandingRoute().go(context); + } else { + context.read().add(MainEnterLocalModeEvent()); + } } - if (state is MainAutoLoginState && - state.failed && - PlatformHelper.isWeb() && - (DotEnvValue.andClientDownloadUrl.isNotEmpty || - DotEnvValue.winClientDownloadUrl.isNotEmpty)) { + if (state is MainEnterLocalModeState && state.success) { + const TipherethRootRoute().go(context); ServerSelectOverlay.of(context)?.hide(); - const WebLandingRoute().go(context); } }, builder: (context, state) { - return Scaffold( + return const Scaffold( body: BootstrapContainer(children: [ BootstrapColumn( xxs: 12, md: 6, - child: UniversalCard( - child: SizedBox( - height: 320, - child: getInitWidget(state), - ), - ), + child: InitWidget(), ), ]), - floatingActionButton: state is MainAutoLoginState && state.failed - ? FloatingActionButton.extended( - onPressed: () { - ServerSelectOverlay.of(context)?.fullscreen(); - }, - icon: const Icon(Icons.arrow_forward), - label: Text(S.of(context).login), - ) - : Container(), ); }, ), ); } - - Widget getInitWidget(MainState state) { - return const InitWidget(); - // if (state is AutoLogging) { - // return const InitWidget(); - // } - // return const WelComeWidget(); - } } class InitWidget extends StatelessWidget { @@ -93,113 +76,69 @@ class InitWidget extends StatelessWidget { @override Widget build(BuildContext context) { return BlocBuilder(builder: (context, state) { + final logoHeight = MediaQuery.sizeOf(context).height / 5; return Column( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'Tui', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 32), - ), - const SizedBox( - width: 4, - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 4), - margin: const EdgeInsets.symmetric(horizontal: 2), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.primary, - borderRadius: BorderRadius.circular(4), + children: SpacingHelper.listSpacing( + height: 16, + children: [ + Image.asset('web/icons/Icon-512.png', height: logoHeight), + Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + ' #', + style: TextStyle( + fontSize: 24.0, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary, + ), ), - child: const Text( - 'Hub', + const SizedBox( + width: 4, + ), + DefaultTextStyle( style: TextStyle( + fontSize: 24.0, fontWeight: FontWeight.bold, - fontSize: 32, - color: Colors.black, + color: Theme.of(context).colorScheme.primary, + ), + child: AnimatedTextKit( + repeatForever: true, + pause: const Duration(milliseconds: 3000), + animatedTexts: [ + TyperAnimatedText( + 'Tiphereth', + speed: const Duration( + milliseconds: 200, + ), + curve: Curves.easeOut, + ), + TyperAnimatedText( + 'Gebura', + speed: const Duration(milliseconds: 200), + curve: Curves.easeOut, + ), + TyperAnimatedText( + 'Yesod', + speed: const Duration(milliseconds: 200), + curve: Curves.easeOut, + ), + ], ), ), - ), - ], - ), - const SizedBox( - height: 32, - ), - if (state is MainAutoLoginState && state.processing) - const SizedBox( - height: 24, - width: 24, - child: CircularProgressIndicator( - strokeWidth: 2, - ), - ) - else - SizedBox( - height: 24, - child: Text( - S.of(context).clickLoginToStart, - style: const TextStyle(fontSize: 16), - ), + ], ), - ], + const UniversalLinearProgressIndicator(), + UniversalTextButton( + child: Text(S.of(context).skipLoading), + onPressed: () { + context.read().add(MainEnterLocalModeEvent()); + }), + ], + ), ); }); } } - -class WelComeWidget extends StatelessWidget { - const WelComeWidget({super.key}); - - @override - Widget build(BuildContext context) { - return Row( - // mainAxisAlignment: MainAxisAlignment.center, - // mainAxisSize: MainAxisSize.max, - children: [ - Text( - ' #', - style: TextStyle( - fontSize: 80.0, - fontWeight: FontWeight.bold, - color: Theme.of(context).colorScheme.primary, - ), - ), - const SizedBox( - width: 4, - ), - DefaultTextStyle( - style: TextStyle( - fontSize: 80.0, - fontWeight: FontWeight.bold, - color: Theme.of(context).colorScheme.primary, - ), - child: AnimatedTextKit( - repeatForever: true, - pause: const Duration(milliseconds: 3000), - animatedTexts: [ - TyperAnimatedText( - 'Tiphereth', - speed: const Duration( - milliseconds: 200, - ), - curve: Curves.easeOut, - ), - TyperAnimatedText( - 'Gebura', - speed: const Duration(milliseconds: 200), - curve: Curves.easeOut, - ), - TyperAnimatedText( - 'Yesod', - speed: const Duration(milliseconds: 200), - curve: Curves.easeOut, - ), - ], - ), - ), - ], - ); - } -} diff --git a/lib/view/pages/tiphereth/tiphereth_frame_page.dart b/lib/view/pages/tiphereth/tiphereth_frame_page.dart index f5987a1..4b4bc9f 100644 --- a/lib/view/pages/tiphereth/tiphereth_frame_page.dart +++ b/lib/view/pages/tiphereth/tiphereth_frame_page.dart @@ -11,14 +11,12 @@ import 'package:tuihub_protos/librarian/v1/wellknown.pb.dart'; import '../../../bloc/main_bloc.dart'; import '../../../bloc/tiphereth/tiphereth_bloc.dart'; import '../../../consts.dart'; -import '../../../l10n/l10n.dart'; import '../../../repo/grpc/l10n.dart'; import '../../helper/connection.dart'; import '../../helper/duration_format.dart'; import '../../layout/bootstrap_container.dart'; import '../../specialized/backdrop_blur.dart'; import '../../universal/universal.dart'; -import '../server_select_overlay.dart'; part 'account_dialog.dart'; part 'my_accounts_card.dart'; @@ -31,21 +29,23 @@ class TipherethFramePage extends StatelessWidget { return Scaffold( body: Column( children: [ - const SizedBox(height: 72), - const MyProfileCard(), + if (ConnectionHelper.isLocal(context)) + const LocalCard() + else + const MyProfileCard(), if (ConnectionHelper.isNotLocal(context)) const Expanded( child: MyAccountsCard(), ), ], ), - floatingActionButton: FloatingActionButton.extended( - onPressed: () { - ServerSelectOverlay.of(context)?.fullscreen(); - }, - icon: Icon(UniversalUI.of(context).icons.logout), - label: Text(S.of(context).changeServer), - ), + // floatingActionButton: FloatingActionButton.extended( + // onPressed: () { + // ServerSelectOverlay.of(context)?.fullscreen(); + // }, + // icon: Icon(UniversalUI.of(context).icons.logout), + // label: Text(S.of(context).changeServer), + // ), ); } } @@ -64,12 +64,13 @@ class MyProfileCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - '${state.currentUser?.id.id.toHexString()}', - style: TextStyle( - color: Theme.of(context).disabledColor, + if (ConnectionHelper.isNotLocal(context)) + Text( + '${state.currentUser?.id.id.toHexString()}', + style: TextStyle( + color: Theme.of(context).disabledColor, + ), ), - ), if (ConnectionHelper.isNotLocal(context)) Text(state.currentUser?.username ?? '', style: const TextStyle( @@ -80,8 +81,9 @@ class MyProfileCard extends StatelessWidget { style: TextStyle( fontSize: 32, )), - if (state.currentUser != null) - Text(userTypeString(state.currentUser!.type)) + if (ConnectionHelper.isNotLocal(context)) + if (state.currentUser != null) + Text(userTypeString(state.currentUser!.type)) ], ), ), @@ -91,3 +93,28 @@ class MyProfileCard extends StatelessWidget { ); } } + +class LocalCard extends StatelessWidget { + const LocalCard({super.key}); + + @override + Widget build(BuildContext context) { + return const UniversalCard( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 24.0), + child: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('本地模式', + style: TextStyle( + fontSize: 32, + )), + Text('添加服务器实例以使用更多功能'), + ], + ), + ), + ), + ); + } +} diff --git a/lib/view/universal/progress.dart b/lib/view/universal/progress.dart new file mode 100644 index 0000000..71c65fc --- /dev/null +++ b/lib/view/universal/progress.dart @@ -0,0 +1,74 @@ +import 'package:fluent_ui/fluent_ui.dart' as fluent; +import 'package:flutter/material.dart' as material; +import 'package:flutter/widgets.dart'; +import 'common.dart'; + +class UniversalCircularProgressIndicator extends StatelessWidget { + const UniversalCircularProgressIndicator({ + super.key, + this.value, + this.backgroundColor, + this.color, + this.strokeWidth = 4.0, + }); + + final double? value; + final Color? backgroundColor; + final Color? color; + final double strokeWidth; + + @override + Widget build(BuildContext context) { + final design = UniversalUI.of(context).design; + + switch (design) { + case UIDesign.material: + return material.CircularProgressIndicator( + value: value, + backgroundColor: backgroundColor, + color: color, + strokeWidth: strokeWidth, + ); + case UIDesign.fluent: + return fluent.ProgressRing( + value: value, + backgroundColor: backgroundColor, + activeColor: color, + strokeWidth: strokeWidth, + ); + } + } +} + +class UniversalLinearProgressIndicator extends StatelessWidget { + const UniversalLinearProgressIndicator({ + super.key, + this.value, + this.backgroundColor, + this.color, + }); + + final double? value; + final Color? backgroundColor; + final Color? color; + + @override + Widget build(BuildContext context) { + final design = UniversalUI.of(context).design; + + switch (design) { + case UIDesign.material: + return material.LinearProgressIndicator( + value: value, + backgroundColor: backgroundColor, + color: color, + ); + case UIDesign.fluent: + return fluent.ProgressBar( + value: value, + backgroundColor: backgroundColor, + activeColor: color, + ); + } + } +} diff --git a/lib/view/universal/universal.dart b/lib/view/universal/universal.dart index 6cc6a27..24d1220 100644 --- a/lib/view/universal/universal.dart +++ b/lib/view/universal/universal.dart @@ -5,5 +5,6 @@ export 'dialog.dart'; export 'form.dart'; export 'input.dart'; export 'list_tile.dart'; +export 'progress.dart'; export 'spacing.dart'; export 'tool_bar.dart'; diff --git a/rust/src/api/simple.rs b/rust/src/api/simple.rs index 79814c4..7b75b3d 100644 --- a/rust/src/api/simple.rs +++ b/rust/src/api/simple.rs @@ -118,7 +118,6 @@ pub fn process_runner( } } - #[cfg(not(any(target_os = "windows", target_os = "linux")))] pub fn process_runner( mode: TraceMode, @@ -205,4 +204,4 @@ pub fn get_system_proxy() -> Result<(bool, String, u16)> { #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))] pub fn get_system_proxy() -> Result<(bool, String, u16)> { Err(err_msg!("Unsupported platform")) -} \ No newline at end of file +} diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs index 947f6e6..3b63d23 100644 --- a/rust/src/frb_generated.rs +++ b/rust/src/frb_generated.rs @@ -25,9 +25,13 @@ // Section: imports -use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; -use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; -use flutter_rust_bridge::{Handler, IntoIntoDart}; +use flutter_rust_bridge::{ + for_generated::{ + byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}, + transform_result_dco, Lifetimeable, Lockable, + }, + Handler, IntoIntoDart, +}; // Section: boilerplate @@ -717,12 +721,15 @@ mod io { // Section: imports - use super::*; - use flutter_rust_bridge::for_generated::byteorder::{ - NativeEndian, ReadBytesExt, WriteBytesExt, + use flutter_rust_bridge::{ + for_generated::{ + byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}, + transform_result_dco, Lifetimeable, Lockable, + }, + Handler, IntoIntoDart, }; - use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; - use flutter_rust_bridge::{Handler, IntoIntoDart}; + + use super::*; // Section: boilerplate @@ -739,14 +746,17 @@ mod web { // Section: imports - use super::*; - use flutter_rust_bridge::for_generated::byteorder::{ - NativeEndian, ReadBytesExt, WriteBytesExt, + use flutter_rust_bridge::{ + for_generated::{ + byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}, + transform_result_dco, wasm_bindgen, + wasm_bindgen::prelude::*, + Lifetimeable, Lockable, + }, + Handler, IntoIntoDart, }; - use flutter_rust_bridge::for_generated::wasm_bindgen; - use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*; - use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; - use flutter_rust_bridge::{Handler, IntoIntoDart}; + + use super::*; // Section: boilerplate