diff --git a/lib/app.dart b/lib/app.dart index 241c6ddd..e76116e4 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -49,11 +49,10 @@ class MyApp extends StatelessWidget { focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: primaryColor))), radioTheme: RadioThemeData( - fillColor: getMaterialStateColor(primaryColor)), + fillColor: getMaterialStateColor(primaryColor),), ), darkTheme: ThemeData.dark().copyWith( primaryColor: primaryColor, - appBarTheme: AppBarTheme(backgroundColor: primaryColor), floatingActionButtonTheme: FloatingActionButtonThemeData( backgroundColor: primaryColor), iconTheme: IconThemeData(color: primaryColor), diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 826037c1..b5dae3cb 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -73,11 +73,10 @@ class ServerProvider extends BusyProvider { } Future startAutoRefresh() async { - Timer.periodic( - Duration( - seconds: locator() - .serverStatusUpdateInterval - .fetch()!), (_) async { + final duration = + locator().serverStatusUpdateInterval.fetch()!; + if (duration == 0) return; + Timer.periodic(Duration(seconds: duration), (_) async { await refreshData(); }); } @@ -86,12 +85,14 @@ class ServerProvider extends BusyProvider { _servers.add(genInfo(info)); locator().put(info); notifyListeners(); + refreshData(); } void delServer(ServerPrivateInfo info) { _servers.removeWhere((e) => e.info == info); locator().delete(info); notifyListeners(); + refreshData(); } void updateServer(ServerPrivateInfo old, ServerPrivateInfo newInfo) { @@ -100,6 +101,7 @@ class ServerProvider extends BusyProvider { _servers[idx].client = genClient(newInfo); locator().update(old, newInfo); notifyListeners(); + refreshData(); } Future _getData(ServerPrivateInfo info, int idx) async { diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 0decc8a1..247853bc 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -3,7 +3,8 @@ class BuildData { static const String name = "ToolBox"; static const int build = 23; - static const String engine = "Flutter 2.5.3 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision 18116933e7 (11 days ago) • 2021-10-15 10:46:35 -0700\nEngine • revision d3ea636dc5\nTools • Dart 2.14.4\n"; + static const String engine = + "Flutter 2.5.3 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision 18116933e7 (11 days ago) • 2021-10-15 10:46:35 -0700\nEngine • revision d3ea636dc5\nTools • Dart 2.14.4\n"; static const String buildAt = "2021-10-26 14:18:53.461371"; static const int modifications = 4; } diff --git a/lib/view/page/convert.dart b/lib/view/page/convert.dart index 30e8cbb1..f29f1e02 100644 --- a/lib/view/page/convert.dart +++ b/lib/view/page/convert.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:clipboard/clipboard.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:toolbox/data/res/color.dart'; @@ -109,7 +110,7 @@ class _ConvertPageState extends State child: SizedBox( width: _media.size.width * 0.3, child: Row( - children: const [Icon(Icons.change_circle), Text('Upside down')], + children: const [Icon(Icons.change_circle), Text(' Upside down')], ), ), onPressed: () { @@ -147,7 +148,18 @@ class _ConvertPageState extends State Widget _buildResult() { return SizedBox( height: _media.size.height * 0.33, - child: _buildInput(_textEditingControllerResult), + child: Stack( + children: [ + _buildInput(_textEditingControllerResult), + Positioned( + right: 7, + top: 7, + child: IconButton( + onPressed: () => + FlutterClipboard.copy(_textEditingControllerResult.text), + icon: const Icon(Icons.copy))) + ], + ), ); } diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart index 5950b9a5..0ab98ec3 100644 --- a/lib/view/page/private_key/edit.dart +++ b/lib/view/page/private_key/edit.dart @@ -55,6 +55,7 @@ class _PrivateKeyEditPageState extends State minLines: 3, maxLines: 10, keyboardType: TextInputType.text, + enableSuggestions: false, decoration: buildDecoration('Private Key', icon: Icons.vpn_key), ), TextField( diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index 654810eb..cdfe9591 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -62,25 +62,30 @@ class _ServerEditPageState extends State with AfterLayoutMixin { TextField( controller: nameController, keyboardType: TextInputType.text, - decoration: buildDecoration('Name', icon: Icons.info), + decoration: + buildDecoration('Name', icon: Icons.info, hint: 'Example'), ), TextField( controller: ipController, keyboardType: TextInputType.text, autocorrect: false, - decoration: buildDecoration('Host', icon: Icons.storage), + enableSuggestions: false, + decoration: buildDecoration('Host', + icon: Icons.storage, hint: 'example.com'), ), TextField( controller: portController, keyboardType: TextInputType.number, - decoration: - buildDecoration('Port', icon: Icons.format_list_numbered), + decoration: buildDecoration('Port', + icon: Icons.format_list_numbered, hint: '22'), ), TextField( controller: usernameController, keyboardType: TextInputType.text, autocorrect: false, - decoration: buildDecoration('User', icon: Icons.account_box), + enableSuggestions: false, + decoration: buildDecoration('User', + icon: Icons.account_box, hint: 'root'), ), const SizedBox(height: 7), Row( @@ -96,7 +101,8 @@ class _ServerEditPageState extends State with AfterLayoutMixin { controller: passwordController, obscureText: true, keyboardType: TextInputType.text, - decoration: buildDecoration('Pwd', icon: Icons.password), + decoration: buildDecoration('Pwd', + icon: Icons.password, hint: 'Password'), onSubmitted: (_) => {}, ) : const SizedBox(), @@ -138,8 +144,23 @@ class _ServerEditPageState extends State with AfterLayoutMixin { floatingActionButton: FloatingActionButton( child: const Icon(Icons.send), onPressed: () { + if (ipController.text == '') { + showSnackBar(context, const Text('Please enter host.')); + return; + } + if (!usePublicKey && passwordController.text == '') { + showSnackBar(context, const Text('Please enter password.')); + return; + } if (usePublicKey && _typeOptionIndex == -1) { showSnackBar(context, const Text('Please select a private key.')); + return; + } + if (usernameController.text == '') { + usernameController.text = 'root'; + } + if (portController.text == '') { + portController.text = '22'; } final authorization = usePublicKey ? {"privateKey": _keyInfo[0], "passphrase": _keyInfo[1]} diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index 6c7af16b..b6975f71 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -121,7 +121,8 @@ class _ServerPageState extends State Text(ss.uptime!, textScaleFactor: 1.0, style: TextStyle( - color: _theme.textTheme.bodyText1!.color!.withAlpha(100), fontSize: 11)) + color: _theme.textTheme.bodyText1!.color!.withAlpha(100), + fontSize: 11)) ], ), const SizedBox( diff --git a/lib/view/page/setting.dart b/lib/view/page/setting.dart index 0e9ed07e..efe186f8 100644 --- a/lib/view/page/setting.dart +++ b/lib/view/page/setting.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_material_color_picker/flutter_material_color_picker.dart'; -import 'package:toolbox/core/utils.dart'; +import 'package:toolbox/data/res/color.dart'; import 'package:toolbox/data/store/setting.dart'; import 'package:toolbox/locator.dart'; import 'package:toolbox/view/widget/round_rect_card.dart'; @@ -15,14 +15,20 @@ class SettingPage extends StatefulWidget { class _SettingPageState extends State { late SettingStore _store; late int _selectedColorValue; - final TextEditingController _intervalController = TextEditingController(); + double _value = 0; + late Color _textColor; + +@override + void didChangeDependencies() { + super.didChangeDependencies(); + _textColor = Theme.of(context).textTheme.bodyText1!.color!; + } @override void initState() { super.initState(); _store = locator(); - _intervalController.text = - _store.serverStatusUpdateInterval.fetch()!.toString(); + _value = _store.serverStatusUpdateInterval.fetch()!.toDouble(); } @override @@ -36,28 +42,40 @@ class _SettingPageState extends State { children: [ RoundRectCard(_buildAppColorPreview()), RoundRectCard( - ListTile( - contentPadding: EdgeInsets.zero, - title: const Text( - 'Server status update interval (seconds)', - style: TextStyle(fontSize: 14), + ExpansionTile( + tilePadding: EdgeInsets.zero, + childrenPadding: EdgeInsets.zero, + title: Text( + 'Server status update interval', + style: TextStyle(fontSize: 14, color: _textColor), textAlign: TextAlign.start, ), - trailing: SizedBox( - width: MediaQuery.of(context).size.width * 0.1, - child: TextField( - textAlign: TextAlign.center, - controller: _intervalController, - keyboardType: TextInputType.number, - onSubmitted: (val) { - _store.serverStatusUpdateInterval.put(int.parse(val)); - showSnackBar( - context, - const Text( - 'This setting will take effect \nthe next time app launch')); - }, - ), + subtitle: const Text( + 'Will take effect the next time app launches.', + style: TextStyle(color: Colors.grey), ), + trailing: Text('${_value.toInt()} s'), + children: [ + Slider( + thumbColor: primaryColor, + activeColor: primaryColor.withOpacity(0.7), + min: 0, + max: 10, + value: _value, + onChanged: (newValue) { + setState(() { + _value = newValue; + }); + }, + onChangeEnd: (val) => + _store.serverStatusUpdateInterval.put(val.toInt()), + label: '${_value.toInt()} seconds', + divisions: 10, + ), + const SizedBox(height: 3,), + _value == 0.0 ? const Text('You set to 0, will not update automatically.') : const SizedBox(), + const SizedBox(height: 13,) + ], ), ) ], @@ -81,9 +99,9 @@ class _SettingPageState extends State { width: 27, ), ), - title: const Text( + title: Text( 'App primary color', - style: TextStyle(fontSize: 14), + style: TextStyle(fontSize: 14, color: _textColor), )); } diff --git a/lib/view/widget/input_decoration.dart b/lib/view/widget/input_decoration.dart index 2f739e10..ff417b06 100644 --- a/lib/view/widget/input_decoration.dart +++ b/lib/view/widget/input_decoration.dart @@ -2,10 +2,11 @@ import 'package:flutter/material.dart'; import 'package:toolbox/data/res/color.dart'; InputDecoration buildDecoration(String label, - {TextStyle? textStyle, IconData? icon}) { + {TextStyle? textStyle, IconData? icon, String? hint}) { return InputDecoration( labelText: label, labelStyle: textStyle, + hintText: hint, icon: Icon( icon, color: primaryColor, diff --git a/pubspec.lock b/pubspec.lock index ce8fc000..bd162b69 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -45,6 +45,13 @@ packages: url: "https://github.com/LollipopKit/circle_chart" source: git version: "0.0.3" + clipboard: + dependency: "direct main" + description: + name: clipboard + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3" clock: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3c99ff02..85edcaf9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,6 +50,7 @@ dependencies: git: url: https://github.com/LollipopKit/circle_chart ref: main + clipboard: ^0.1.3 dev_dependencies: