diff --git a/README.md b/README.md
index 44db3754..21e89d51 100644
--- a/README.md
+++ b/README.md
@@ -9,10 +9,10 @@ A new Flutter project which provide a chart view to display server status data a
-
+
|
-
+
|
@@ -22,13 +22,20 @@ A new Flutter project which provide a chart view to display server status data a
-
+
|
|
+
+
+
+
+ |
+
+
# Support
Status|Platform
diff --git a/lib/data/model/app/navigation_item.dart b/lib/data/model/app/navigation_item.dart
new file mode 100644
index 00000000..d59683ec
--- /dev/null
+++ b/lib/data/model/app/navigation_item.dart
@@ -0,0 +1,8 @@
+import 'package:flutter/material.dart';
+
+class NavigationItem {
+ final IconData icon;
+ final String title;
+
+ NavigationItem(this.icon, this.title);
+}
diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart
index 1edce1e3..e7c8a8b8 100644
--- a/lib/data/res/build_data.dart
+++ b/lib/data/res/build_data.dart
@@ -2,8 +2,9 @@
class BuildData {
static const String name = "ServerBox";
- static const int build = 91;
- static const String engine = "Flutter 2.10.0 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision 5f105a6ca7 (7 days ago) • 2022-02-01 14:15:42 -0800\nEngine • revision 776efd2034\nTools • Dart 2.16.0 • DevTools 2.9.2\n";
- static const String buildAt = "2022-02-08 19:01:55.450937";
- static const int modifications = 3;
+ static const int build = 93;
+ static const String engine =
+ "Flutter 2.10.0 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision 5f105a6ca7 (7 days ago) • 2022-02-01 14:15:42 -0800\nEngine • revision 776efd2034\nTools • Dart 2.16.0 • DevTools 2.9.2\n";
+ static const String buildAt = "2022-02-08 20:57:54.707031";
+ static const int modifications = 9;
}
diff --git a/lib/data/res/tab.dart b/lib/data/res/tab.dart
index fb289c39..fa7dc7fc 100644
--- a/lib/data/res/tab.dart
+++ b/lib/data/res/tab.dart
@@ -1 +1,9 @@
+import 'package:flutter/material.dart';
+import 'package:toolbox/data/model/app/navigation_item.dart';
+
final List tabs = ['Servers', 'En/Decode', 'Ping'];
+final List tabItems = [
+ NavigationItem(Icons.computer, 'Server'),
+ NavigationItem(Icons.code, 'Convert'),
+ NavigationItem(Icons.network_check, 'Ping'),
+ ];
diff --git a/lib/view/page/debug.dart b/lib/view/page/debug.dart
index 0f8396b3..0f357782 100644
--- a/lib/view/page/debug.dart
+++ b/lib/view/page/debug.dart
@@ -14,7 +14,7 @@ class _DebugPageState extends State {
Widget build(BuildContext context) {
return Scaffold(
appBar:
- AppBar(title: const Text('Terminal'), backgroundColor: Colors.black),
+ AppBar(title: const Text('App log'), backgroundColor: Colors.black),
body: _buildTerminal(context),
backgroundColor: Colors.black,
);
diff --git a/lib/view/page/home.dart b/lib/view/page/home.dart
index 4ccc194b..11bdcec7 100644
--- a/lib/view/page/home.dart
+++ b/lib/view/page/home.dart
@@ -1,13 +1,16 @@
import 'package:after_layout/after_layout.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_advanced_drawer/flutter_advanced_drawer.dart';
import 'package:get_it/get_it.dart';
import 'package:toolbox/core/analysis.dart';
import 'package:toolbox/core/build_mode.dart';
import 'package:toolbox/core/route.dart';
import 'package:toolbox/core/update.dart';
import 'package:toolbox/core/utils.dart';
+import 'package:toolbox/data/model/app/navigation_item.dart';
import 'package:toolbox/data/provider/server.dart';
import 'package:toolbox/data/res/build_data.dart';
+import 'package:toolbox/data/res/color.dart';
import 'package:toolbox/data/res/icon/common.dart';
import 'package:toolbox/data/res/tab.dart';
import 'package:toolbox/data/res/url.dart';
@@ -36,23 +39,26 @@ class _MyHomePageState extends State
SingleTickerProviderStateMixin,
AfterLayoutMixin,
WidgetsBindingObserver {
- late final TabController _tabController;
late final ServerProvider _serverProvider;
+ late final PageController _pageController;
+ late final AdvancedDrawerController _advancedDrawerController;
+ late int _selectIndex;
+ late double _width;
@override
void initState() {
super.initState();
_serverProvider = locator();
WidgetsBinding.instance?.addObserver(this);
- _tabController = TabController(
- initialIndex: locator().launchPage.fetch()!,
- length: tabs.length,
- vsync: this);
- _tabController.addListener(() {
- if (_tabController.index == 0) {
- FocusScope.of(context).unfocus();
- }
- });
+ _selectIndex = locator().launchPage.fetch()!;
+ _pageController = PageController(initialPage: _selectIndex);
+ _advancedDrawerController = AdvancedDrawerController();
+ }
+
+ @override
+ void didChangeDependencies() {
+ super.didChangeDependencies();
+ _width = MediaQuery.of(context).size.width;
}
@override
@@ -77,37 +83,123 @@ class _MyHomePageState extends State
Widget build(BuildContext context) {
setTransparentNavigationBar(context);
super.build(context);
- return Scaffold(
- appBar: AppBar(
- title: GestureDetector(
- onLongPress: () =>
- AppRoute(const DebugPage(), 'Debug Page').go(context),
- child: const Text(BuildData.name),
- ),
- bottom: TabBar(
- indicatorColor: widget.primaryColor,
- tabs: tabs.map((e) => Tab(text: e)).toList(),
- controller: _tabController,
+ return AdvancedDrawer(
+ controller: _advancedDrawerController,
+ animationCurve: Curves.easeInOutCirc,
+ animationDuration: const Duration(milliseconds: 300),
+ animateChildDecoration: true,
+ rtlOpening: false,
+ disabledGestures: true,
+ childDecoration: const BoxDecoration(
+ // NOTICE: Uncomment if you want to add shadow behind the page.
+ // Keep in mind that it may cause animation jerks.
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black12,
+ blurRadius: 0.0,
+ ),
+ ],
+ borderRadius: BorderRadius.all(Radius.circular(16)),
),
+ drawer: _buildDrawer(),
+ child: Scaffold(
+ appBar: AppBar(
+ title: Text(tabItems[_selectIndex].title),
+ actions: [
+ IconButton(
+ icon: const Icon(Icons.developer_mode, size: 23),
+ tooltip: 'Debug',
+ onPressed: () =>
+ AppRoute(const DebugPage(), 'Debug Page').go(context),
+ ),
+ ],
+ leading: IconButton(
+ onPressed: () => _advancedDrawerController.showDrawer(),
+ icon: ValueListenableBuilder(
+ valueListenable: _advancedDrawerController,
+ builder: (_, value, __) {
+ return AnimatedSwitcher(
+ duration: const Duration(milliseconds: 250),
+ child: Icon(
+ value.visible ? Icons.clear : Icons.menu,
+ key: ValueKey(value.visible),
+ ),
+ );
+ },
+ ),
+ ),
+ ),
+ body: PageView(
+ physics: const ClampingScrollPhysics(),
+ controller: _pageController,
+ onPageChanged: (i) {
+ FocusScope.of(context).unfocus();
+ _selectIndex = i;
+ setState(() {});
+ },
+ children: const [ServerPage(), ConvertPage(), PingPage()],
+ ),
+ bottomNavigationBar: _buildBottom(context),
+ ));
+ }
+
+ Widget _buildItem(int idx, NavigationItem item, bool isSelected) {
+ bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
+ final width = _width / tabItems.length;
+ return AnimatedContainer(
+ duration: const Duration(milliseconds: 377),
+ curve: Curves.fastOutSlowIn,
+ height: 50,
+ width: isSelected ? width : width - 17,
+ decoration: BoxDecoration(
+ color: isSelected
+ ? isDarkMode
+ ? Colors.white12
+ : Colors.black.withOpacity(0.07)
+ : Colors.transparent,
+ borderRadius: const BorderRadius.all(Radius.circular(50))),
+ child: IconButton(
+ icon: Icon(item.icon),
+ tooltip: item.title,
+ splashRadius: width / 3.3,
+ padding: const EdgeInsets.only(left: 17, right: 17),
+ onPressed: () {
+ setState(() {
+ _pageController.animateToPage(idx,
+ duration: const Duration(milliseconds: 677),
+ curve: Curves.fastLinearToSlowEaseIn);
+ });
+ },
),
- drawer: _buildDrawer(),
- body: TabBarView(controller: _tabController, children: [
- ServerPage(_tabController),
- const ConvertPage(),
- const PingPage()
- ]),
);
}
+ Widget _buildBottom(BuildContext context) {
+ return SafeArea(
+ child: Container(
+ height: 56,
+ padding: const EdgeInsets.only(left: 8, top: 4, bottom: 4, right: 8),
+ width: _width,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: tabItems.map((item) {
+ int itemIndex = tabItems.indexOf(item);
+ return _buildItem(itemIndex, item, _selectIndex == itemIndex);
+ }).toList(),
+ ),
+ ));
+ }
+
Widget _buildDrawer() {
- return Drawer(
- child: ListView(
- padding: EdgeInsets.zero,
+ return SafeArea(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
children: [
- UserAccountsDrawerHeader(
- accountName: const Text(BuildData.name),
- accountEmail: Text(_buildVersionStr()),
- currentAccountPicture: _buildIcon(),
+ _buildIcon(),
+ const Text(BuildData.name),
+ Text(_buildVersionStr()),
+ SizedBox(
+ height: MediaQuery.of(context).size.height * 0.07,
),
ListTile(
leading: const Icon(Icons.settings),
@@ -149,9 +241,19 @@ class _MyHomePageState extends State
}
Widget _buildIcon() {
- return ConstrainedBox(
- constraints: const BoxConstraints(maxHeight: 60, maxWidth: 60),
- child: appIcon,
+ return Stack(
+ alignment: Alignment.center,
+ children: [
+ ConstrainedBox(
+ constraints: const BoxConstraints(maxHeight: 53, maxWidth: 53),
+ child: Container(
+ color: primaryColor,
+ )),
+ ConstrainedBox(
+ constraints: const BoxConstraints(maxHeight: 83, maxWidth: 83),
+ child: appIcon,
+ )
+ ],
);
}
diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart
index 6a8f1fa1..5e598423 100644
--- a/lib/view/page/server/tab.dart
+++ b/lib/view/page/server/tab.dart
@@ -7,6 +7,7 @@ import 'package:marquee/marquee.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:toolbox/core/route.dart';
+import 'package:toolbox/core/utils.dart';
import 'package:toolbox/data/model/server/server.dart';
import 'package:toolbox/data/model/server/server_connection_state.dart';
import 'package:toolbox/data/model/server/server_private_info.dart';
@@ -21,8 +22,7 @@ import 'package:toolbox/view/page/snippet/list.dart';
import 'package:toolbox/view/widget/round_rect_card.dart';
class ServerPage extends StatefulWidget {
- final TabController tabController;
- const ServerPage(this.tabController, {Key? key}) : super(key: key);
+ const ServerPage({Key? key}) : super(key: key);
@override
_ServerPageState createState() => _ServerPageState();
@@ -50,9 +50,6 @@ class _ServerPageState extends State
_media = MediaQuery.of(context);
_theme = Theme.of(context);
_primaryColor = primaryColor;
- if (widget.tabController.index == 0) {
- FocusScope.of(context).unfocus();
- }
}
@override
@@ -207,11 +204,10 @@ class _ServerPageState extends State
onChanged: (value) {
final item = value as MenuItem;
switch (item) {
- case MenuItems.sftp:
- //Do something
- break;
case MenuItems.apt:
- //Do something
+ case MenuItems.sftp:
+ showSnackBar(
+ context, const Text('Now is not supported'));
break;
case MenuItems.snippet:
AppRoute(
@@ -404,7 +400,7 @@ class MenuItems {
static const List