new: full screen

This commit is contained in:
lollipopkit
2023-06-08 22:17:26 +08:00
parent 342c3ea295
commit 0ddfc4ec75
12 changed files with 370 additions and 5 deletions

View File

@@ -480,6 +480,12 @@ abstract class S {
/// **'Found {count} update'** /// **'Found {count} update'**
String foundNUpdate(Object count); String foundNUpdate(Object count);
/// No description provided for @fullScreen.
///
/// In en, this message translates to:
/// **'Full screen mode'**
String get fullScreen;
/// No description provided for @getPushTokenFailed. /// No description provided for @getPushTokenFailed.
/// ///
/// In en, this message translates to: /// In en, this message translates to:

View File

@@ -212,6 +212,9 @@ class SDe extends S {
return 'Update $count gefunden'; return 'Update $count gefunden';
} }
@override
String get fullScreen => 'Full screen mode';
@override @override
String get getPushTokenFailed => 'Push-Token kann nicht abgerufen werden'; String get getPushTokenFailed => 'Push-Token kann nicht abgerufen werden';

View File

@@ -212,6 +212,9 @@ class SEn extends S {
return 'Found $count update'; return 'Found $count update';
} }
@override
String get fullScreen => 'Full screen mode';
@override @override
String get getPushTokenFailed => 'Can\'t fetch push token'; String get getPushTokenFailed => 'Can\'t fetch push token';

View File

@@ -212,6 +212,9 @@ class SZh extends S {
return '找到 $count 个更新'; return '找到 $count 个更新';
} }
@override
String get fullScreen => '全屏模式';
@override @override
String get getPushTokenFailed => '未能获取到推送token'; String get getPushTokenFailed => '未能获取到推送token';

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/locale.dart'; import 'package:toolbox/core/extension/locale.dart';
import 'package:toolbox/view/page/full_screen.dart';
import 'core/utils/ui.dart'; import 'core/utils/ui.dart';
import 'data/res/build_data.dart'; import 'data/res/build_data.dart';
@@ -18,6 +19,7 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
setTransparentNavigationBar(context); setTransparentNavigationBar(context);
primaryColor = Color(_setting.primaryColor.fetch()!); primaryColor = Color(_setting.primaryColor.fetch()!);
final fullScreen = _setting.fullScreen.fetch()!;
return ValueListenableBuilder<int>( return ValueListenableBuilder<int>(
valueListenable: _setting.themeMode.listenable(), valueListenable: _setting.themeMode.listenable(),
@@ -75,7 +77,7 @@ class MyApp extends StatelessWidget {
color: Colors.black, color: Colors.black,
), ),
), ),
home: const HomePage(), home: fullScreen ? const FullScreenPage() : const HomePage(),
); );
}, },
); );

View File

@@ -74,7 +74,7 @@ Future<T?> showRoundDialog<T>({
Widget buildSwitch( Widget buildSwitch(
BuildContext context, BuildContext context,
StoreProperty<bool> prop, { StoreProperty<bool> prop, {
Function(bool)? func, void Function(bool)? func,
}) { }) {
return ValueListenableBuilder( return ValueListenableBuilder(
valueListenable: prop.listenable(), valueListenable: prop.listenable(),
@@ -167,3 +167,8 @@ void showSnippetDialog(
], ],
); );
} }
void hideStatusBar() {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky,
overlays: []);
}

View File

@@ -6,7 +6,7 @@ import '../res/default.dart';
class SettingStore extends PersistentStore { class SettingStore extends PersistentStore {
StoreProperty<int> get primaryColor => property( StoreProperty<int> get primaryColor => property(
'primaryColor', 'primaryColor',
defaultValue: defaultPrimaryColor.value, defaultValue: 4287106639,
); );
StoreProperty<int> get serverStatusUpdateInterval => property( StoreProperty<int> get serverStatusUpdateInterval => property(
@@ -66,4 +66,7 @@ class SettingStore extends PersistentStore {
// Editor theme // Editor theme
StoreProperty<String> get editorTheme => StoreProperty<String> get editorTheme =>
property('editorTheme', defaultValue: defaultEditorTheme); property('editorTheme', defaultValue: defaultEditorTheme);
StoreProperty<bool> get fullScreen =>
property('fullScreen', defaultValue: false);
} }

View File

@@ -64,6 +64,7 @@
"font": "Font", "font": "Font",
"fontSize": "Font size", "fontSize": "Font size",
"foundNUpdate": "Found {count} update", "foundNUpdate": "Found {count} update",
"fullScreen": "Full screen mode",
"getPushTokenFailed": "Can't fetch push token", "getPushTokenFailed": "Can't fetch push token",
"gettingToken": "Getting token...", "gettingToken": "Getting token...",
"goto": "Go to", "goto": "Go to",

View File

@@ -64,6 +64,7 @@
"font": "字体", "font": "字体",
"fontSize": "字体大小", "fontSize": "字体大小",
"foundNUpdate": "找到 {count} 个更新", "foundNUpdate": "找到 {count} 个更新",
"fullScreen": "全屏模式",
"getPushTokenFailed": "未能获取到推送token", "getPushTokenFailed": "未能获取到推送token",
"gettingToken": "正在获取Token...", "gettingToken": "正在获取Token...",
"goto": "前往", "goto": "前往",

View File

@@ -0,0 +1,327 @@
import 'package:after_layout/after_layout.dart';
import 'package:circle_chart/circle_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:get_it/get_it.dart';
import 'package:provider/provider.dart';
import 'package:toolbox/core/route.dart';
import 'package:toolbox/data/provider/server.dart';
import 'package:toolbox/data/res/ui.dart';
import 'package:toolbox/locator.dart';
import '../../core/analysis.dart';
import '../../core/update.dart';
import '../../core/utils/ui.dart';
import '../../data/model/server/server.dart';
import '../../data/model/server/server_private_info.dart';
import '../../data/model/server/server_status.dart';
import '../../data/res/color.dart';
import 'server/detail.dart';
import 'server/edit.dart';
import 'setting.dart';
class FullScreenPage extends StatefulWidget {
const FullScreenPage({Key? key}) : super(key: key);
@override
_FullScreenPageState createState() => _FullScreenPageState();
}
class _FullScreenPageState extends State<FullScreenPage>
with AfterLayoutMixin, AutomaticKeepAliveClientMixin {
late S _s;
late MediaQueryData _media;
late ThemeData _theme;
final _pageController = PageController(initialPage: 0);
final _serverProvider = locator<ServerProvider>();
@override
void initState() {
super.initState();
hideStatusBar();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
_media = MediaQuery.of(context);
_theme = Theme.of(context);
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
body: SafeArea(
child: RotatedBox(
quarterTurns: 3,
child: Stack(
children: [
_buildMain(),
Positioned(
top: 0,
left: 0,
child: _buildSettingBtn(),
),
],
),
),
),
);
}
Widget _buildSettingBtn() {
return IconButton(
onPressed: () => AppRoute(
const SettingPage(),
'Setting',
).go(context),
icon: const Icon(Icons.settings, color: Colors.grey));
}
Widget _buildMain() {
return Consumer<ServerProvider>(builder: (_, pro, __) {
if (pro.serverOrder.isEmpty) {
return Center(
child: TextButton(
onPressed: () => AppRoute(
const ServerEditPage(),
'Add server info page',
).go(context),
child: Text(
_s.addAServer,
style: const TextStyle(fontSize: 27),
)),
);
}
return PageView.builder(
controller: _pageController,
itemCount: pro.servers.length,
itemBuilder: (_, idx) {
final id = pro.serverOrder[idx];
final s = pro.servers[id];
if (s == null) {
return placeholder;
}
return _buildRealServerCard(s.status, s.state, s.spi);
},
);
});
}
Widget _buildRealServerCard(
ServerStatus ss,
ServerState cs,
ServerPrivateInfo spi,
) {
final rootDisk = ss.disk.firstWhere((element) => element.loc == '/');
return InkWell(
onTap: () => AppRoute(
ServerDetailPage(spi.id),
'server detail page',
).go(context),
child: Stack(
children: [
Positioned(top: 0, left: 0, right: 0, child: _buildServerCardTitle(ss, cs, spi)),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: _media.size.width * 0.1),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildPercentCircle(ss.cpu.usedPercent()),
_buildPercentCircle(ss.mem.usedPercent * 100),
_buildIOData(
'Conn:\n${ss.tcp.maxConn}', 'Fail:\n${ss.tcp.fail}'),
_buildIOData(
'Total:\n${rootDisk.size}',
'Used:\n${rootDisk.usedPercent}%',
)
],
),
SizedBox(height: _media.size.width * 0.1),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildExplainText('CPU'),
_buildExplainText('Mem'),
_buildExplainText('Net'),
_buildExplainText('Disk'),
],
),
],
),
],
),
);
}
Widget _buildServerCardTitle(
ServerStatus ss,
ServerState cs,
ServerPrivateInfo spi,
) {
return Padding(
padding: EdgeInsets.symmetric(vertical: _media.size.width * 0.05),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
spi.name,
style:
const TextStyle(fontWeight: FontWeight.bold, fontSize: 19),
textScaleFactor: 1.0,
textAlign: TextAlign.center,
),
const Icon(
Icons.keyboard_arrow_right,
size: 21,
color: Colors.grey,
)
],
),
height13,
_buildTopRightText(ss, cs),
],
),
);
}
Widget _buildTopRightText(ServerStatus ss, ServerState cs) {
final topRightStr = _getTopRightStr(
cs,
ss.temps.first,
ss.uptime,
ss.failedInfo,
);
return Text(
topRightStr,
style: textSize12Grey,
textScaleFactor: 1.0,
);
}
Widget _buildExplainText(String text) {
return SizedBox(
width: _media.size.height * 0.2,
child: Text(
text,
style: const TextStyle(fontSize: 13),
textAlign: TextAlign.center,
textScaleFactor: 1.0,
),
);
}
String _getTopRightStr(
ServerState cs,
double? temp,
String upTime,
String? failedInfo,
) {
switch (cs) {
case ServerState.disconnected:
return _s.disconnected;
case ServerState.connected:
final tempStr = temp == null ? '' : '${temp.toStringAsFixed(1)}°C';
final items = [tempStr, upTime];
final str = items.where((element) => element.isNotEmpty).join(' | ');
if (str.isEmpty) return _s.serverTabLoading;
return str;
case ServerState.connecting:
return _s.serverTabConnecting;
case ServerState.failed:
if (failedInfo == null) {
return _s.serverTabFailed;
}
if (failedInfo.contains('encypted')) {
return _s.serverTabPlzSave;
}
return failedInfo;
default:
return _s.serverTabUnkown;
}
}
Widget _buildIOData(String up, String down) {
final statusTextStyle = TextStyle(
fontSize: 13, color: _theme.textTheme.bodyLarge!.color!.withAlpha(177));
return SizedBox(
width: _media.size.height * 0.23,
child: Column(
children: [
const SizedBox(height: 5),
Text(
up,
style: statusTextStyle,
textAlign: TextAlign.center,
textScaleFactor: 1.0,
),
const SizedBox(height: 3),
Text(
down,
style: statusTextStyle,
textAlign: TextAlign.center,
textScaleFactor: 1.0,
)
],
),
);
}
Widget _buildPercentCircle(double percent) {
if (percent <= 0) percent = 0.01;
if (percent >= 100) percent = 99.9;
return SizedBox(
width: _media.size.height * 0.23,
child: Stack(
children: [
Center(
child: CircleChart(
progressColor: primaryColor,
progressNumber: percent,
animationDuration: const Duration(milliseconds: 377),
maxNumber: 100,
width: _media.size.width * 0.22,
height: _media.size.width * 0.22,
),
),
Positioned.fill(
child: Center(
child: Text(
'${percent.toStringAsFixed(1)}%',
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 15),
textScaleFactor: 1.0,
),
),
),
],
),
);
}
@override
bool get wantKeepAlive => true;
@override
Future<void> afterFirstLayout(BuildContext context) async {
await GetIt.I.allReady();
await _serverProvider.loadLocalData();
await _serverProvider.refreshData();
await doUpdate(context);
if (!Analysis.enabled) {
await Analysis.init();
}
}
}

View File

@@ -112,7 +112,6 @@ class _ServerPageState extends State<ServerPage>
}), }),
itemBuilder: (_, index) => _buildEachServerCard( itemBuilder: (_, index) => _buildEachServerCard(
pro.servers[filtered[index]], pro.servers[filtered[index]],
index,
), ),
itemCount: filtered.length, itemCount: filtered.length,
); );
@@ -166,7 +165,7 @@ class _ServerPageState extends State<ServerPage>
); );
} }
Widget _buildEachServerCard(Server? si, int index) { Widget _buildEachServerCard(Server? si) {
if (si == null) { if (si == null) {
return placeholder; return placeholder;
} }

View File

@@ -127,6 +127,7 @@ class _SettingPageState extends State<SettingPage> {
_buildAppColor(), _buildAppColor(),
_buildLaunchPage(), _buildLaunchPage(),
_buildCheckUpdate(), _buildCheckUpdate(),
_buildFullScreen(),
]; ];
if (isIOS) { if (isIOS) {
children.add(_buildPushToken()); children.add(_buildPushToken());
@@ -660,4 +661,15 @@ class _SettingPageState extends State<SettingPage> {
}, },
); );
} }
Widget _buildFullScreen() {
return ListTile(
title: Text(_s.fullScreen),
trailing: buildSwitch(
context,
_setting.fullScreen,
func: (_) => _showRestartSnackbar(),
),
);
}
} }