diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e48bee..9ab63a0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 1.0.4
+* 增加主题切换功能,各种颜色主题随意切换
+* 修改无法停止任务的bug
+* 修改脚本管理页面json解析失败的bug
+* 修改变更配置文件没有及时刷新UI的bug
+* 增加版本更新提醒功能(需要手机能联通github)
+* 登录页面长按青龙logo可以呼出网络请求日志,再次长按可关闭
+* 打开系统最近任务时展示APP的名称
+* 优化使用体验
+
## 1.0.3
* 解决2.10.12及以下版本无法登录的问题
diff --git a/README.md b/README.md
index 4d242aa..ff135ed 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,8 @@ iOS端暂无上架打算,用户自行下载main分支源码编译安装
+
-
@@ -35,9 +35,9 @@ iOS端暂无上架打算,用户自行下载main分支源码编译安装
+
### 不支持的功能
-
>* 应用设置
>* 通知设置
diff --git a/art/14.jpg b/art/14.jpg
new file mode 100644
index 0000000..3353034
Binary files /dev/null and b/art/14.jpg differ
diff --git a/assets/images/update_bg_app_top.png b/assets/images/update_bg_app_top.png
new file mode 100644
index 0000000..d97da82
Binary files /dev/null and b/assets/images/update_bg_app_top.png differ
diff --git a/assets/images/update_ic_close.png b/assets/images/update_ic_close.png
new file mode 100644
index 0000000..29e55e9
Binary files /dev/null and b/assets/images/update_ic_close.png differ
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index a07c4ef..fb6eca4 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -5,15 +5,21 @@ PODS:
- Toast
- move_to_background (0.0.1):
- Flutter
+ - package_info_plus (0.4.5):
+ - Flutter
- shared_preferences_ios (0.0.1):
- Flutter
- Toast (4.0.0)
+ - url_launcher_ios (0.0.1):
+ - Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- move_to_background (from `.symlinks/plugins/move_to_background/ios`)
+ - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
+ - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
trunk:
@@ -26,15 +32,21 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/fluttertoast/ios"
move_to_background:
:path: ".symlinks/plugins/move_to_background/ios"
+ package_info_plus:
+ :path: ".symlinks/plugins/package_info_plus/ios"
shared_preferences_ios:
:path: ".symlinks/plugins/shared_preferences_ios/ios"
+ url_launcher_ios:
+ :path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
fluttertoast: 6122fa75143e992b1d3470f61000f591a798cc58
move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
+ package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
shared_preferences_ios: aef470a42dc4675a1cdd50e3158b42e3d1232b32
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
+ url_launcher_ios: 02f1989d4e14e998335b02b67a7590fa34f971af
PODFILE CHECKSUM: aea2ed8a4b05dec076f6f7cea39202b1133ed51c
diff --git a/lib/base/http/api.dart b/lib/base/http/api.dart
index 577da93..903faac 100644
--- a/lib/base/http/api.dart
+++ b/lib/base/http/api.dart
@@ -87,7 +87,7 @@ class Api {
static Future> stopTasks(List crons) async {
return await Http.put(
- Url.runTasks,
+ Url.stopTasks,
crons,
);
}
diff --git a/lib/base/http/url.dart b/lib/base/http/url.dart
index 4b6345d..6e919ab 100644
--- a/lib/base/http/url.dart
+++ b/lib/base/http/url.dart
@@ -76,4 +76,6 @@ class Url {
}
return false;
}
+
+ static String checkUpdateUrl = "https://raw.githubusercontent.com/qinglong-app/qinglong_app/main/version";
}
diff --git a/lib/base/routes.dart b/lib/base/routes.dart
index 0a51954..caafac2 100644
--- a/lib/base/routes.dart
+++ b/lib/base/routes.dart
@@ -15,6 +15,7 @@ import 'package:qinglong_app/module/others/scripts/script_edit_page.dart';
import 'package:qinglong_app/module/others/scripts/script_page.dart';
import 'package:qinglong_app/module/others/task_log/task_log_detail_page.dart';
import 'package:qinglong_app/module/others/task_log/task_log_page.dart';
+import 'package:qinglong_app/module/others/theme_page.dart';
import 'package:qinglong_app/module/others/update_password_page.dart';
import 'package:qinglong_app/module/task/add_task_page.dart';
import 'package:qinglong_app/module/task/task_bean.dart';
@@ -39,6 +40,7 @@ class Routes {
static const String routeDependency = "/Dependency";
static const String routeUpdatePassword = "/updatePassword";
static const String routeAbout = "/about";
+ static const String routeTheme = "/theme";
static Route? generateRoute(RouteSettings settings) {
switch (settings.name) {
@@ -56,7 +58,8 @@ class Routes {
return CupertinoPageRoute(builder: (context) => const AddTaskPage());
}
case routeAddDependency:
- return CupertinoPageRoute(builder: (context) => const AddDependencyPage());
+ return CupertinoPageRoute(
+ builder: (context) => const AddDependencyPage());
case routeAddEnv:
if (settings.arguments != null) {
return CupertinoPageRoute(
@@ -122,6 +125,10 @@ class Routes {
return CupertinoPageRoute(
builder: (context) => const AboutPage(),
);
+ case routeTheme:
+ return CupertinoPageRoute(
+ builder: (context) => const ThemePage(),
+ );
case routeScriptUpdate:
return CupertinoPageRoute(
builder: (context) => ScriptEditPage(
diff --git a/lib/base/sp_const.dart b/lib/base/sp_const.dart
index 647ce53..b4ae7b4 100644
--- a/lib/base/sp_const.dart
+++ b/lib/base/sp_const.dart
@@ -4,3 +4,4 @@ String spUserName = "username";
String spPassWord = "password";
String spTheme = "dart_mode";
String spSecretLogined = "secret_logined";
+String spCustomColor = "customColor";
diff --git a/lib/base/theme.dart b/lib/base/theme.dart
index 7d78418..5150117 100644
--- a/lib/base/theme.dart
+++ b/lib/base/theme.dart
@@ -3,21 +3,25 @@ import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qinglong_app/base/sp_const.dart';
+import 'package:qinglong_app/base/userinfo_viewmodel.dart';
+import 'package:qinglong_app/main.dart';
import 'package:qinglong_app/utils/codeeditor_theme.dart';
import 'package:qinglong_app/utils/sp_utils.dart';
var themeProvider = ChangeNotifierProvider((ref) => ThemeViewModel());
-const Color _primaryColor = Color(0xFF299343);
-
-get primaryColor => _primaryColor;
+Color _primaryColor = const Color(0xFF299343);
class ThemeViewModel extends ChangeNotifier {
- ThemeData currentTheme = lightTheme;
+ late ThemeData currentTheme;
+
bool _isInDarkMode = false;
+ Color primaryColor = const Color(0xFF299343);
ThemeColors themeColor = LightThemeColors();
ThemeViewModel() {
+ _primaryColor = Color(getIt().primaryColor);
+ primaryColor = Color(getIt().primaryColor);
var brightness = SchedulerBinding.instance!.window.platformBrightness;
_isInDarkMode = brightness == Brightness.dark;
changeThemeReal(_isInDarkMode, false);
@@ -31,10 +35,10 @@ class ThemeViewModel extends ChangeNotifier {
_isInDarkMode = dark;
SpUtil.putBool(spTheme, dark);
if (!dark) {
- currentTheme = lightTheme;
+ currentTheme = getLightTheme();
themeColor = LightThemeColors();
} else {
- currentTheme = darkTheme;
+ currentTheme = getDartTheme();
themeColor = DartThemeColors();
}
if (notify) {
@@ -44,149 +48,161 @@ class ThemeViewModel extends ChangeNotifier {
get darkMode => _isInDarkMode;
+ void changePrimaryColor(Color color) {
+ _primaryColor = color;
+ primaryColor = color;
+ getIt().updateCustomColor(color.value);
+ changeThemeReal(SpUtil.getBool(spTheme, defValue: false), true);
+ }
+
void changeTheme() {
changeThemeReal(!SpUtil.getBool(spTheme, defValue: false), true);
}
-}
-ThemeData darkTheme = ThemeData.dark().copyWith(
- brightness: Brightness.dark,
- primaryColor: const Color(0xffffffff),
- scaffoldBackgroundColor: Colors.black,
- appBarTheme: const AppBarTheme(
- backgroundColor: Colors.black,
- titleTextStyle: TextStyle(
- color: Colors.white,
- fontSize: 18,
- ),
- ),
- inputDecorationTheme: const InputDecorationTheme(
- labelStyle: TextStyle(color: _primaryColor),
- focusedBorder: UnderlineInputBorder(
- borderSide: BorderSide(
+ ThemeData getLightTheme() {
+ return ThemeData.light().copyWith(
+ brightness: Brightness.light,
+ primaryColor: _primaryColor,
+ colorScheme: ColorScheme.light(
+ secondary: _primaryColor,
+ primary: _primaryColor,
+ ),
+ scaffoldBackgroundColor: const Color(0xfff5f5f5),
+ inputDecorationTheme: InputDecorationTheme(
+ labelStyle: TextStyle(color: _primaryColor),
+ focusedBorder: UnderlineInputBorder(
+ borderSide: BorderSide(
+ color: _primaryColor,
+ ),
+ ),
+ border: const UnderlineInputBorder(
+ borderSide: BorderSide(
+ color: Color(0xff999999),
+ ),
+ ),
+ enabledBorder: const UnderlineInputBorder(
+ borderSide: BorderSide(
+ color: Color(0xff999999),
+ ),
+ ),
+ ),
+ appBarTheme: AppBarTheme(
+ backgroundColor: _primaryColor,
+ titleTextStyle: const TextStyle(
+ color: Colors.white,
+ fontSize: 18,
+ ),
+ ),
+ bottomNavigationBarTheme: BottomNavigationBarThemeData(
+ selectedItemColor: _primaryColor,
+ ),
+ buttonTheme: ButtonThemeData(
+ buttonColor: _primaryColor,
+ ),
+ progressIndicatorTheme: ProgressIndicatorThemeData(
color: _primaryColor,
),
- ),
- border: UnderlineInputBorder(
- borderSide: BorderSide(
- color: Color(0xff999999),
+ tabBarTheme: TabBarTheme(
+ labelStyle: const TextStyle(
+ fontSize: 14,
+ ),
+ unselectedLabelStyle: const TextStyle(
+ fontSize: 14,
+ ),
+ labelColor: _primaryColor,
+ unselectedLabelColor: const Color(0xff999999),
+ indicator: UnderlineTabIndicator(
+ borderSide: BorderSide(color: _primaryColor),
+ ),
),
- ),
- enabledBorder: UnderlineInputBorder(
- borderSide: BorderSide(
- color: Color(0xff999999),
+ toggleableActiveColor: _primaryColor,
+ checkboxTheme: CheckboxThemeData(
+ checkColor: MaterialStateProperty.resolveWith(
+ (Set states) {
+ if (states.contains(MaterialState.disabled)) {
+ return Colors.transparent;
+ }
+ if (states.contains(MaterialState.selected)) {
+ return Colors.white;
+ }
+ return Colors.black;
+ },
+ ),
),
- ),
- ),
- tabBarTheme: const TabBarTheme(
- labelStyle: TextStyle(
- fontSize: 14,
- ),
- unselectedLabelStyle: TextStyle(
- fontSize: 14,
- ),
- labelColor: Color(0xffffffff),
- unselectedLabelColor: Color(0xff999999),
- ),
- colorScheme: const ColorScheme.light(
- secondary: _primaryColor,
- primary: _primaryColor,
- ),
- toggleableActiveColor: _primaryColor,
- checkboxTheme: CheckboxThemeData(
- checkColor: MaterialStateProperty.resolveWith(
- (Set states) {
- if (states.contains(MaterialState.disabled)) {
- return Colors.transparent;
- }
- if (states.contains(MaterialState.selected)) {
- return Colors.white;
- }
- return Colors.white;
- },
- ),
- ),
- cupertinoOverrideTheme: const NoDefaultCupertinoThemeData(
- brightness: Brightness.dark,
- primaryColor: Color(0xffffffff),
- scaffoldBackgroundColor: Colors.black,
- ),
-);
-ThemeData lightTheme = ThemeData.light().copyWith(
- brightness: Brightness.light,
- primaryColor: _primaryColor,
- colorScheme: const ColorScheme.light(
- secondary: _primaryColor,
- primary: _primaryColor,
- ),
- scaffoldBackgroundColor: const Color(0xfff5f5f5),
- inputDecorationTheme: const InputDecorationTheme(
- labelStyle: TextStyle(color: _primaryColor),
- focusedBorder: UnderlineInputBorder(
- borderSide: BorderSide(
- color: _primaryColor,
+ cupertinoOverrideTheme: NoDefaultCupertinoThemeData(
+ brightness: Brightness.light,
+ primaryColor: _primaryColor,
+ scaffoldBackgroundColor: const Color(0xfff5f5f5),
),
- ),
- border: UnderlineInputBorder(
- borderSide: BorderSide(
- color: Color(0xff999999),
+ );
+ }
+
+ ThemeData getDartTheme() {
+ return ThemeData.dark().copyWith(
+ brightness: Brightness.dark,
+ primaryColor: const Color(0xffffffff),
+ scaffoldBackgroundColor: Colors.black,
+ appBarTheme: const AppBarTheme(
+ backgroundColor: Colors.black,
+ titleTextStyle: TextStyle(
+ color: Colors.white,
+ fontSize: 18,
+ ),
),
- ),
- enabledBorder: UnderlineInputBorder(
- borderSide: BorderSide(
- color: Color(0xff999999),
+ inputDecorationTheme: InputDecorationTheme(
+ labelStyle: TextStyle(color: _primaryColor),
+ focusedBorder: UnderlineInputBorder(
+ borderSide: BorderSide(
+ color: _primaryColor,
+ ),
+ ),
+ border: const UnderlineInputBorder(
+ borderSide: BorderSide(
+ color: Color(0xff999999),
+ ),
+ ),
+ enabledBorder: const UnderlineInputBorder(
+ borderSide: BorderSide(
+ color: Color(0xff999999),
+ ),
+ ),
),
- ),
- ),
- appBarTheme: const AppBarTheme(
- backgroundColor: _primaryColor,
- titleTextStyle: TextStyle(
- color: Colors.white,
- fontSize: 18,
- ),
- ),
- bottomNavigationBarTheme: const BottomNavigationBarThemeData(
- selectedItemColor: _primaryColor,
- ),
- buttonTheme: const ButtonThemeData(
- buttonColor: _primaryColor,
- ),
- progressIndicatorTheme: const ProgressIndicatorThemeData(
- color: _primaryColor,
- ),
- tabBarTheme: const TabBarTheme(
- labelStyle: TextStyle(
- fontSize: 14,
- ),
- unselectedLabelStyle: TextStyle(
- fontSize: 14,
- ),
- labelColor: _primaryColor,
- unselectedLabelColor: Color(0xff999999),
- indicator: UnderlineTabIndicator(
- borderSide: BorderSide(color: _primaryColor),
- ),
- ),
- toggleableActiveColor: _primaryColor,
- checkboxTheme: CheckboxThemeData(
- checkColor: MaterialStateProperty.resolveWith(
- (Set states) {
- if (states.contains(MaterialState.disabled)) {
- return Colors.transparent;
- }
- if (states.contains(MaterialState.selected)) {
- return Colors.white;
- }
- return Colors.black;
- },
- ),
- ),
- cupertinoOverrideTheme: const NoDefaultCupertinoThemeData(
- brightness: Brightness.light,
- primaryColor: _primaryColor,
- scaffoldBackgroundColor: Color(0xfff5f5f5),
- ),
-);
+ tabBarTheme: const TabBarTheme(
+ labelStyle: TextStyle(
+ fontSize: 14,
+ ),
+ unselectedLabelStyle: TextStyle(
+ fontSize: 14,
+ ),
+ labelColor: Color(0xffffffff),
+ unselectedLabelColor: Color(0xff999999),
+ ),
+ colorScheme: ColorScheme.light(
+ secondary: _primaryColor,
+ primary: _primaryColor,
+ ),
+ toggleableActiveColor: _primaryColor,
+ checkboxTheme: CheckboxThemeData(
+ checkColor: MaterialStateProperty.resolveWith(
+ (Set states) {
+ if (states.contains(MaterialState.disabled)) {
+ return Colors.transparent;
+ }
+ if (states.contains(MaterialState.selected)) {
+ return Colors.white;
+ }
+ return Colors.white;
+ },
+ ),
+ ),
+ cupertinoOverrideTheme: const NoDefaultCupertinoThemeData(
+ brightness: Brightness.dark,
+ primaryColor: Color(0xffffffff),
+ scaffoldBackgroundColor: Colors.black,
+ ),
+ );
+ }
+}
abstract class ThemeColors {
Color settingBgColor();
diff --git a/lib/base/userinfo_viewmodel.dart b/lib/base/userinfo_viewmodel.dart
index ab33602..3da7a1f 100644
--- a/lib/base/userinfo_viewmodel.dart
+++ b/lib/base/userinfo_viewmodel.dart
@@ -8,11 +8,13 @@ class UserInfoViewModel {
String? _userName;
String? _passWord;
bool _useSecertLogined = false;
+ int _primaryColor = 0xFF299343;
UserInfoViewModel() {
String userInfoJson = SpUtil.getString(spUserInfo);
_userName = SpUtil.getString(spUserName);
_passWord = SpUtil.getString(spPassWord);
+ _primaryColor = SpUtil.getInt(spCustomColor, defValue: 0xFF299343);
_useSecertLogined = SpUtil.getBool(spSecretLogined, defValue: false);
_host = SpUtil.getString(spHost, defValue: '');
@@ -39,6 +41,11 @@ class UserInfoViewModel {
SpUtil.putBool(spSecretLogined, _useSecertLogined);
}
+ void updateCustomColor(int color) {
+ _primaryColor = color;
+ SpUtil.putInt(spCustomColor, color);
+ }
+
void updateHost(String host) {
_host = host;
SpUtil.putString(spHost, host);
@@ -54,6 +61,8 @@ class UserInfoViewModel {
bool get useSecretLogined => _useSecertLogined;
+ int get primaryColor => _primaryColor;
+
bool isLogined() {
return token != null && token!.isNotEmpty;
}
diff --git a/lib/main.dart b/lib/main.dart
index 6c2103c..9b12a29 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -57,7 +57,8 @@ class QlAppState extends ConsumerState {
child: MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance!.window).copyWith(textScaleFactor: 1,),
child: MaterialApp(
- locale: const Locale('zh', 'cn'),
+ title: "青龙",
+ locale: const Locale('zh', 'CN'),
navigatorKey: navigatorState,
theme: ref.watch(themeProvider).currentTheme,
onGenerateRoute: (setting) {
@@ -65,9 +66,6 @@ class QlAppState extends ConsumerState {
},
home: Builder(
builder: (context) {
- if (!kReleaseMode) {
- showDebugBtn(context, btnColor: Colors.blue);
- }
return getIt().isLogined() ? const HomePage() : const LoginPage();
},
),
diff --git a/lib/module/a.dart b/lib/module/a.dart
deleted file mode 100644
index 8b13789..0000000
--- a/lib/module/a.dart
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/lib/module/config/config_edit_page.dart b/lib/module/config/config_edit_page.dart
index b7e7268..bf47439 100644
--- a/lib/module/config/config_edit_page.dart
+++ b/lib/module/config/config_edit_page.dart
@@ -49,7 +49,7 @@ class _ConfigEditPageState extends ConsumerState {
if (response.success) {
"提交成功".toast();
ref.read(configProvider).loadContent(widget.title);
- Navigator.of(context).pop();
+ Navigator.of(context).pop(widget.title);
} else {
(response.message ?? "").toast();
}
@@ -80,7 +80,7 @@ class _ConfigEditPageState extends ConsumerState {
child: TextField(
focusNode: node,
style: TextStyle(
- color: ref.read(themeProvider).themeColor.descColor(),
+ color: ref.read(themeProvider).themeColor.titleColor(),
fontSize: 14,
),
controller: _controller,
diff --git a/lib/module/config/config_page.dart b/lib/module/config/config_page.dart
index d51b9ff..de4b25d 100644
--- a/lib/module/config/config_page.dart
+++ b/lib/module/config/config_page.dart
@@ -5,6 +5,7 @@ import 'package:qinglong_app/base/base_state_widget.dart';
import 'package:qinglong_app/base/routes.dart';
import 'package:qinglong_app/base/theme.dart';
import 'package:qinglong_app/base/ui/abs_underline_tabindicator.dart';
+import 'package:qinglong_app/base/ui/empty_widget.dart';
import 'package:qinglong_app/main.dart';
import 'config_viewmodel.dart';
@@ -29,6 +30,9 @@ class ConfigPageState extends State
Widget build(BuildContext context) {
return BaseStateWidget(
builder: (ref, model, child) {
+ if (model.list.isEmpty) {
+ return const EmptyWidget();
+ }
_tabController ??=
TabController(length: model.list.length, vsync: this);
@@ -89,6 +93,11 @@ class ConfigPageState extends State
"title": ref.read(configProvider).list[_tabController?.index ?? 0].title,
"content": ref.read(configProvider).content[
ref.read(configProvider).list[_tabController?.index ?? 0].title]
+ }).then((value) async {
+ if (value != null && (value as String).isNotEmpty) {
+ await ref.read(configProvider).loadContent(value);
+ setState(() {});
+ }
});
}
}
diff --git a/lib/module/env/env_bean.dart b/lib/module/env/env_bean.dart
index d54c3d5..87dfb45 100644
--- a/lib/module/env/env_bean.dart
+++ b/lib/module/env/env_bean.dart
@@ -15,7 +15,7 @@ class EnvBean {
EnvBean.fromJson(Map json) {
value = json['value'];
sId = json.containsKey('_id') ? json['_id'].toString() : (json.containsKey('id') ? json['id'].toString() : "");
- created = json['created'];
+ created = int.tryParse(json['created'].toString());
status = json['status'];
timestamp = json['timestamp'];
name = json['name'];
diff --git a/lib/module/env/env_detail_page.dart b/lib/module/env/env_detail_page.dart
index fdc3540..913e7db 100644
--- a/lib/module/env/env_detail_page.dart
+++ b/lib/module/env/env_detail_page.dart
@@ -249,7 +249,7 @@ class _TaskDetailPageState extends ConsumerState {
child: Text(
"确定",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
),
),
onPressed: () async {
diff --git a/lib/module/env/env_page.dart b/lib/module/env/env_page.dart
index 0ba5be8..c9f22b3 100644
--- a/lib/module/env/env_page.dart
+++ b/lib/module/env/env_page.dart
@@ -238,13 +238,24 @@ class EnvItemCell extends StatelessWidget {
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
- border: Border.all(color: primaryColor, width: 1),
+ border: Border.all(color: ref.watch(themeProvider).primaryColor, width: 1),
),
child: Text(
"$index",
- style: TextStyle(color: primaryColor, fontSize: 12),
+ style: TextStyle(color: ref.watch(themeProvider).primaryColor, fontSize: 12),
),
),
+ const SizedBox(
+ width: 5,
+ ),
+ bean.status == 1
+ ? const Icon(
+ Icons.dnd_forwardslash,
+ size: 12,
+ color: Colors.red,
+ )
+ : const SizedBox.shrink(),
+
const SizedBox(
width: 5,
),
@@ -261,16 +272,6 @@ class EnvItemCell extends StatelessWidget {
),
),
),
- const SizedBox(
- width: 5,
- ),
- bean.status == 1
- ? const Icon(
- Icons.dnd_forwardslash,
- size: 12,
- color: Colors.red,
- )
- : const SizedBox.shrink(),
const Spacer(),
],
),
@@ -331,7 +332,7 @@ class EnvItemCell extends StatelessWidget {
child: Text(
"确定",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
),
),
onPressed: () {
diff --git a/lib/module/home/home_page.dart b/lib/module/home/home_page.dart
index 4bee986..ca37d09 100644
--- a/lib/module/home/home_page.dart
+++ b/lib/module/home/home_page.dart
@@ -9,6 +9,7 @@ import 'package:qinglong_app/module/env/env_page.dart';
import 'package:qinglong_app/module/others/other_page.dart';
import 'package:qinglong_app/module/task/task_page.dart';
import 'package:move_to_background/move_to_background.dart';
+import 'package:qinglong_app/utils/update_utils.dart';
class HomePage extends ConsumerStatefulWidget {
const HomePage({Key? key}) : super(key: key);
@@ -30,6 +31,9 @@ class _HomePageState extends ConsumerState {
initTitles();
_title = titles[0].title;
super.initState();
+ WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
+ update();
+ });
}
@override
@@ -185,6 +189,16 @@ class _HomePageState extends ConsumerState {
),
);
}
+
+ void update() async {
+ String? result = await UpdateUtils().checkUpdate();
+ if (result != null && result.isNotEmpty) {
+ UpdateDialog updateDialog = UpdateDialog(context, title: "发现新版本", updateContent: "版本号:v$result", onUpdate: () {
+ UpdateUtils.launchURL(result);
+ });
+ updateDialog.show();
+ }
+ }
}
class IndexBean {
diff --git a/lib/module/login/login_bean.dart b/lib/module/login/login_bean.dart
index c686f77..1b26726 100644
--- a/lib/module/login/login_bean.dart
+++ b/lib/module/login/login_bean.dart
@@ -21,7 +21,7 @@ class LoginBean {
token = json['token'];
lastip = json['lastip'];
lastaddr = json['lastaddr'];
- lastlogon = json['lastlogon'];
+ lastlogon = int.tryParse(json['lastlogon'].toString());
retries = json['retries'];
platform = json['platform'];
}
diff --git a/lib/module/login/login_page.dart b/lib/module/login/login_page.dart
index 90a07d1..a638c1d 100644
--- a/lib/module/login/login_page.dart
+++ b/lib/module/login/login_page.dart
@@ -1,3 +1,4 @@
+import 'package:dio_log/dio_log.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -9,6 +10,7 @@ import 'package:qinglong_app/base/userinfo_viewmodel.dart';
import 'package:qinglong_app/main.dart';
import 'package:qinglong_app/module/login/user_bean.dart';
import 'package:qinglong_app/utils/extension.dart';
+import 'package:qinglong_app/utils/update_utils.dart';
import 'package:qinglong_app/utils/utils.dart';
import 'package:flip_card/flip_card.dart';
@@ -22,7 +24,8 @@ class LoginPage extends ConsumerStatefulWidget {
}
class _LoginPageState extends ConsumerState {
- final TextEditingController _hostController = TextEditingController(text: getIt().host);
+ final TextEditingController _hostController =
+ TextEditingController(text: getIt().host);
final TextEditingController _userNameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final TextEditingController _cIdController = TextEditingController();
@@ -38,7 +41,8 @@ class _LoginPageState extends ConsumerState {
super.initState();
useSecretLogin = getIt().useSecretLogined;
- if (getIt().userName != null && getIt().userName!.isNotEmpty) {
+ if (getIt().userName != null &&
+ getIt().userName!.isNotEmpty) {
if (getIt().useSecretLogined) {
_cIdController.text = getIt().userName!;
} else {
@@ -48,7 +52,8 @@ class _LoginPageState extends ConsumerState {
} else {
rememberPassword = false;
}
- if (getIt().passWord != null && getIt().passWord!.isNotEmpty) {
+ if (getIt().passWord != null &&
+ getIt().passWord!.isNotEmpty) {
if (getIt().useSecretLogined) {
_cSecretController.text = getIt().passWord!;
} else {
@@ -57,6 +62,7 @@ class _LoginPageState extends ConsumerState {
}
getIt().updateToken("");
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
+ update();
if (useSecretLogin) {
cardKey.currentState?.toggleCard();
}
@@ -107,9 +113,28 @@ class _LoginPageState extends ConsumerState {
),
),
),
- Image.asset(
- "assets/images/ql.png",
- height: 45,
+ GestureDetector(
+ onDoubleTap: () {
+ if (debugBtnIsShow()) {
+ dismissDebugBtn();
+ } else {
+ showDebugBtn(context,
+ btnColor: ref
+ .watch(themeProvider)
+ .primaryColor);
+ }
+ WidgetsBinding.instance?.endOfFrame;
+ },
+ child: ColorFiltered(
+ colorFilter: ColorFilter.mode(
+ ref.watch(themeProvider).primaryColor,
+ BlendMode.srcIn,
+ ),
+ child: Image.asset(
+ "assets/images/ql.png",
+ height: 45,
+ ),
+ ),
),
],
),
@@ -136,6 +161,7 @@ class _LoginPageState extends ConsumerState {
),
FlipCard(
key: cardKey,
+ flipOnTouch: false,
onFlipDone: (back) {
useSecretLogin = back;
setState(() {});
@@ -164,7 +190,8 @@ class _LoginPageState extends ConsumerState {
},
controller: _userNameController,
decoration: const InputDecoration(
- contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
+ contentPadding:
+ EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入用户名",
),
autofocus: false,
@@ -186,7 +213,8 @@ class _LoginPageState extends ConsumerState {
controller: _passwordController,
obscureText: true,
decoration: const InputDecoration(
- contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
+ contentPadding:
+ EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入密码",
),
autofocus: false,
@@ -220,7 +248,8 @@ class _LoginPageState extends ConsumerState {
},
controller: _cIdController,
decoration: const InputDecoration(
- contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
+ contentPadding:
+ EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入client_id",
),
autofocus: false,
@@ -242,7 +271,8 @@ class _LoginPageState extends ConsumerState {
controller: _cSecretController,
obscureText: true,
decoration: const InputDecoration(
- contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
+ contentPadding:
+ EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入client_secret",
),
autofocus: false,
@@ -280,18 +310,19 @@ class _LoginPageState extends ConsumerState {
GestureDetector(
onTap: () {
cardKey.currentState?.toggleCard();
- WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
+ WidgetsBinding.instance
+ ?.addPostFrameCallback((timeStamp) {
setState(() {});
});
},
child: Text(
- loginByUserName() ? "client_id登录" : "用户名密码登录",
+ loginByUserName() ? "client_id登录" : "账号登录",
style: const TextStyle(
fontSize: 14,
),
),
),
- SizedBox(
+ const SizedBox(
width: 10,
),
],
@@ -313,7 +344,12 @@ class _LoginPageState extends ConsumerState {
padding: const EdgeInsets.symmetric(
vertical: 5,
),
- color: canClickLoginBtn() ? primaryColor : primaryColor.withOpacity(0.4),
+ color: canClickLoginBtn()
+ ? ref.watch(themeProvider).primaryColor
+ : ref
+ .watch(themeProvider)
+ .primaryColor
+ .withOpacity(0.4),
child: isLoading
? const CupertinoActivityIndicator()
: const Text(
@@ -325,12 +361,15 @@ class _LoginPageState extends ConsumerState {
onPressed: () {
Http.pushedLoginPage = false;
Utils.hideKeyBoard(context);
- getIt().updateHost(_hostController.text);
+ getIt()
+ .updateHost(_hostController.text);
Http.clear();
if (loginByUserName()) {
- login(_userNameController.text, _passwordController.text);
+ login(_userNameController.text,
+ _passwordController.text);
} else {
- login(_cIdController.text, _cSecretController.text);
+ login(_cIdController.text,
+ _cSecretController.text);
}
},
),
@@ -367,7 +406,8 @@ class _LoginPageState extends ConsumerState {
loginSuccess(response, userName, password);
} else if (loginByUserName() && response.code == 401) {
//可能用户使用的是老版本qinglong
- HttpResponse oldResponse = await Api.loginOld(userName, password);
+ HttpResponse oldResponse =
+ await Api.loginOld(userName, password);
if (oldResponse.success) {
loginSuccess(oldResponse, userName, password);
} else {
@@ -398,11 +438,14 @@ class _LoginPageState extends ConsumerState {
setState(() {});
}
- void loginSuccess(HttpResponse response, String userName, String password) {
+ void loginSuccess(
+ HttpResponse response, String userName, String password) {
getIt().updateToken(response.bean?.token ?? "");
getIt().useSecretLogin(!loginByUserName());
if (rememberPassword) {
getIt().updateUserName(userName, password);
+ } else {
+ getIt().updateUserName("", "");
}
Navigator.of(context).pushReplacementNamed(Routes.routeHomePage);
}
@@ -412,9 +455,11 @@ class _LoginPageState extends ConsumerState {
if (_hostController.text.isEmpty) return false;
if (!loginByUserName()) {
- return _cIdController.text.isNotEmpty && _cSecretController.text.isNotEmpty;
+ return _cIdController.text.isNotEmpty &&
+ _cSecretController.text.isNotEmpty;
} else {
- return _userNameController.text.isNotEmpty && _passwordController.text.isNotEmpty;
+ return _userNameController.text.isNotEmpty &&
+ _passwordController.text.isNotEmpty;
}
}
@@ -460,12 +505,13 @@ class _LoginPageState extends ConsumerState {
child: Text(
"确定",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
),
),
onPressed: () async {
Navigator.of(context).pop(true);
- HttpResponse response = await Api.loginTwo(userName, password, twoFact);
+ HttpResponse response =
+ await Api.loginTwo(userName, password, twoFact);
if (response.success) {
loginSuccess(response, userName, password);
} else {
@@ -481,4 +527,15 @@ class _LoginPageState extends ConsumerState {
}
});
}
+
+ void update() async {
+ String? result = await UpdateUtils().checkUpdate();
+ if (result != null && result.isNotEmpty) {
+ UpdateDialog updateDialog = UpdateDialog(context,
+ title: "发现新版本", updateContent: "版本号:v${result}", onUpdate: () {
+ UpdateUtils.launchURL(result);
+ });
+ updateDialog.show();
+ }
+ }
}
diff --git a/lib/module/others/about_page.dart b/lib/module/others/about_page.dart
index 6a21fcd..ba2a206 100644
--- a/lib/module/others/about_page.dart
+++ b/lib/module/others/about_page.dart
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qinglong_app/base/ql_app_bar.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:qinglong_app/base/theme.dart';
+import 'package:qinglong_app/utils/update_utils.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../main.dart';
@@ -23,6 +24,20 @@ class _AboutPageState extends ConsumerState {
void initState() {
super.initState();
getInfo();
+
+ WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
+ update();
+ });
+ }
+
+ void update() async {
+ String? result = await UpdateUtils().checkUpdate(true);
+ if (result != null && result.isNotEmpty) {
+ UpdateDialog updateDialog = UpdateDialog(context, title: "发现新版本", updateContent: "版本号:v${result}", onUpdate: () {
+ UpdateUtils.launchURL(result);
+ });
+ updateDialog.show();
+ }
}
@override
@@ -76,7 +91,7 @@ class _AboutPageState extends ConsumerState {
child: Text(
"Telegram频道",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
fontSize: 16,
),
),
@@ -92,7 +107,7 @@ class _AboutPageState extends ConsumerState {
child: Text(
"版本更新",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
fontSize: 16,
),
),
@@ -107,7 +122,7 @@ class _AboutPageState extends ConsumerState {
child: Text(
"项目地址",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
fontSize: 16,
),
),
diff --git a/lib/module/others/dependencies/add_dependency_page.dart b/lib/module/others/dependencies/add_dependency_page.dart
index f1ba40b..e762532 100644
--- a/lib/module/others/dependencies/add_dependency_page.dart
+++ b/lib/module/others/dependencies/add_dependency_page.dart
@@ -37,10 +37,6 @@ class _AddDependencyPageState extends ConsumerState {
title: "新增依赖",
actions: [
InkWell(
- onLongPress: () {
- showDebugBtn(context, btnColor: Colors.blue);
- WidgetsBinding.instance?.endOfFrame;
- },
onTap: () {
submit();
},
diff --git a/lib/module/others/dependencies/dependency_bean.dart b/lib/module/others/dependencies/dependency_bean.dart
index 88ca001..e596c53 100644
--- a/lib/module/others/dependencies/dependency_bean.dart
+++ b/lib/module/others/dependencies/dependency_bean.dart
@@ -24,10 +24,10 @@ class DependencyBean {
DependencyBean.fromJson(Map json) {
sId = json['_id'];
- created = json['created'];
+ created = int.tryParse(json['created'].toString());
status = json['status'];
type = json['type'];
- timestamp = json['timestamp'];
+ timestamp = json['timestamp'].toString();
name = json['name'];
log = json['log'].cast();
remark = json['remark'];
diff --git a/lib/module/others/dependencies/dependency_page.dart b/lib/module/others/dependencies/dependency_page.dart
index 594e9a7..aad98b5 100644
--- a/lib/module/others/dependencies/dependency_page.dart
+++ b/lib/module/others/dependencies/dependency_page.dart
@@ -231,7 +231,7 @@ class DependencyCell extends ConsumerWidget {
bean.status == 1
? Icon(
CupertinoIcons.checkmark_circle,
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
size: 16,
)
: (bean.status == 2
@@ -348,7 +348,7 @@ class DependencyCell extends ConsumerWidget {
child: Text(
"确定",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
),
),
onPressed: () {
diff --git a/lib/module/others/login_log/login_log_bean.dart b/lib/module/others/login_log/login_log_bean.dart
index 95ea622..5305ee1 100644
--- a/lib/module/others/login_log/login_log_bean.dart
+++ b/lib/module/others/login_log/login_log_bean.dart
@@ -13,7 +13,7 @@ class LoginLogBean {
{this.timestamp, this.address, this.ip, this.platform, this.status});
LoginLogBean.fromJson(Map json) {
- timestamp = json['timestamp'];
+ timestamp = int.tryParse(json['timestamp'].toString());
address = json['address'];
ip = json['ip'];
platform = json['platform'];
diff --git a/lib/module/others/login_log/login_log_page.dart b/lib/module/others/login_log/login_log_page.dart
index 7ceb496..8c985a7 100644
--- a/lib/module/others/login_log/login_log_page.dart
+++ b/lib/module/others/login_log/login_log_page.dart
@@ -86,7 +86,7 @@ class _LoginLogPageState extends ConsumerState with LazyLoadState<
trailing: item.status == 0
? Icon(
CupertinoIcons.checkmark_circle,
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
size: 16,
)
: const Icon(
diff --git a/lib/module/others/other_page.dart b/lib/module/others/other_page.dart
index 339bf68..f85f3ca 100644
--- a/lib/module/others/other_page.dart
+++ b/lib/module/others/other_page.dart
@@ -59,7 +59,10 @@ class _OtherPageState extends ConsumerState {
Text(
"脚本管理",
style: TextStyle(
- color: ref.watch(themeProvider).themeColor.titleColor(),
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .titleColor(),
fontSize: 16,
),
),
@@ -92,7 +95,10 @@ class _OtherPageState extends ConsumerState {
Text(
"依赖管理",
style: TextStyle(
- color: ref.watch(themeProvider).themeColor.titleColor(),
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .titleColor(),
fontSize: 16,
),
),
@@ -116,16 +122,21 @@ class _OtherPageState extends ConsumerState {
);
},
child: Padding(
- padding: const EdgeInsets.symmetric(
- vertical: 8,
- horizontal: 15,
+ padding: const EdgeInsets.only(
+ top: 8,
+ bottom: 15,
+ left: 15,
+ right: 15,
),
child: Row(
children: [
Text(
"任务日志",
style: TextStyle(
- color: ref.watch(themeProvider).themeColor.titleColor(),
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .titleColor(),
fontSize: 16,
),
),
@@ -178,7 +189,10 @@ class _OtherPageState extends ConsumerState {
Text(
"登录日志",
style: TextStyle(
- color: ref.watch(themeProvider).themeColor.titleColor(),
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .titleColor(),
fontSize: 16,
),
),
@@ -206,9 +220,11 @@ class _OtherPageState extends ConsumerState {
},
behavior: HitTestBehavior.opaque,
child: Padding(
- padding: const EdgeInsets.symmetric(
- vertical: 10,
- horizontal: 15,
+ padding: const EdgeInsets.only(
+ top: 8,
+ bottom: 15,
+ left: 15,
+ right: 15,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
@@ -217,7 +233,10 @@ class _OtherPageState extends ConsumerState {
Text(
"修改密码",
style: TextStyle(
- color: ref.watch(themeProvider).themeColor.titleColor(),
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .titleColor(),
fontSize: 16,
),
),
@@ -261,7 +280,8 @@ class _OtherPageState extends ConsumerState {
Text(
"夜间模式",
style: TextStyle(
- color: ref.watch(themeProvider).themeColor.titleColor(),
+ color:
+ ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 16,
),
),
@@ -278,6 +298,44 @@ class _OtherPageState extends ConsumerState {
const Divider(
indent: 15,
),
+ GestureDetector(
+ behavior: HitTestBehavior.opaque,
+ onTap: () {
+ Navigator.of(context).pushNamed(
+ Routes.routeTheme,
+ );
+ },
+ child: Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 15,
+ vertical: 5,
+ ),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ "主题设置",
+ style: TextStyle(
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .titleColor(),
+ fontSize: 16,
+ ),
+ ),
+ const Spacer(),
+ const Icon(
+ CupertinoIcons.right_chevron,
+ size: 16,
+ ),
+ ],
+ ),
+ ),
+ ),
+ const Divider(
+ indent: 15,
+ ),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
@@ -299,7 +357,10 @@ class _OtherPageState extends ConsumerState {
Text(
"关于",
style: TextStyle(
- color: ref.watch(themeProvider).themeColor.titleColor(),
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .titleColor(),
fontSize: 16,
),
),
@@ -353,12 +414,13 @@ class _OtherPageState extends ConsumerState {
child: Text(
"确定",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
),
),
onPressed: () {
getIt().updateToken("");
- Navigator.of(context).pushReplacementNamed(Routes.routeLogin);
+ Navigator.of(context)
+ .pushReplacementNamed(Routes.routeLogin);
},
),
],
diff --git a/lib/module/others/scripts/script_bean.dart b/lib/module/others/scripts/script_bean.dart
index 4370716..3e65f64 100644
--- a/lib/module/others/scripts/script_bean.dart
+++ b/lib/module/others/scripts/script_bean.dart
@@ -5,24 +5,14 @@ import 'package:json_conversion_annotation/json_conversion_annotation.dart';
class ScriptBean {
String? title;
String? value;
- String? key;
- double? mtime;
bool? disabled;
List? children;
- ScriptBean(
- {this.title,
- this.value,
- this.key,
- this.mtime,
- this.disabled,
- this.children});
+ ScriptBean({this.title, this.value, this.disabled, this.children});
ScriptBean.fromJson(Map json) {
title = json['title'];
value = json['value'];
- key = json['key'];
- mtime = json['mtime'];
disabled = json['disabled'];
if (json['children'] != null) {
children = [];
@@ -36,8 +26,6 @@ class ScriptBean {
final Map data = new Map();
data['title'] = this.title;
data['value'] = this.value;
- data['key'] = this.key;
- data['mtime'] = this.mtime;
data['disabled'] = this.disabled;
if (this.children != null) {
data['children'] = this.children!.map((v) => v.toJson()).toList();
@@ -53,17 +41,13 @@ class ScriptBean {
class ScriptChildren {
String? title;
String? value;
- String? key;
- double? mtime;
String? parent;
- ScriptChildren({this.title, this.value, this.key, this.mtime, this.parent});
+ ScriptChildren({this.title, this.value, this.parent});
ScriptChildren.fromJson(Map json) {
title = json['title'];
value = json['value'];
- key = json['key'];
- mtime = json['mtime'];
parent = json['parent'];
}
@@ -71,8 +55,6 @@ class ScriptChildren {
final Map data = new Map();
data['title'] = this.title;
data['value'] = this.value;
- data['key'] = this.key;
- data['mtime'] = this.mtime;
data['parent'] = this.parent;
return data;
}
diff --git a/lib/module/others/scripts/script_detail_page.dart b/lib/module/others/scripts/script_detail_page.dart
index 2a1c06c..3460f6c 100644
--- a/lib/module/others/scripts/script_detail_page.dart
+++ b/lib/module/others/scripts/script_detail_page.dart
@@ -98,7 +98,7 @@ class _ScriptDetailPageState extends ConsumerState with LazyLo
child: Text(
"确定",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
),
),
onPressed: () async {
diff --git a/lib/module/others/theme_page.dart b/lib/module/others/theme_page.dart
new file mode 100644
index 0000000..80b4f50
--- /dev/null
+++ b/lib/module/others/theme_page.dart
@@ -0,0 +1,478 @@
+import 'dart:math';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_colorpicker/flutter_colorpicker.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:qinglong_app/base/ql_app_bar.dart';
+import 'package:qinglong_app/base/theme.dart';
+
+class ThemePage extends ConsumerStatefulWidget {
+ const ThemePage({Key? key}) : super(key: key);
+
+ @override
+ _ThemePageState createState() => _ThemePageState();
+}
+
+class _ThemePageState extends ConsumerState {
+ late Color _primaryColor;
+ List colors = [];
+ double colorHeight = 40;
+ double smallColorHeight = 8;
+
+ @override
+ void initState() {
+ super.initState();
+ _primaryColor = ref.read(themeProvider).primaryColor;
+ colors.add(const Color(0xFF299343));
+ colors.addAll([
+ Colors.red,
+ Colors.pink,
+ Colors.purple,
+ Colors.deepPurple,
+ Colors.indigo,
+ Colors.blue,
+ Colors.lightBlue,
+ Colors.cyan,
+ Colors.teal,
+ Colors.green,
+ Colors.lightGreen,
+ Colors.lime,
+ Colors.yellow,
+ Colors.amber,
+ Colors.orange,
+ Colors.deepOrange,
+ Colors.brown,
+ Colors.blueGrey,
+ ]);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: const Color(0xff999999),
+ appBar: QlAppBar(
+ title: '主题设置',
+ canBack: true,
+ actions: [
+ InkWell(
+ onTap: () {
+ submit();
+ },
+ child: const Padding(
+ padding: EdgeInsets.symmetric(
+ horizontal: 15,
+ ),
+ child: Center(
+ child: Text(
+ "保存",
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 16,
+ ),
+ ),
+ ),
+ ),
+ )
+ ],
+ ),
+ body: SafeArea(
+ bottom: true,
+ child: Column(
+ children: [
+ const SizedBox(
+ height: 15,
+ ),
+ Expanded(
+ child: SizedBox(
+ height:
+ MediaQuery.of(context).size.height * 3 / 4 - kToolbarHeight,
+ child: Row(
+ children: [
+ const SizedBox(
+ width: 20,
+ ),
+ Expanded(
+ child: ClipRRect(
+ borderRadius: BorderRadius.circular(15),
+ child: Scaffold(
+ appBar: AppBar(
+ backgroundColor: _primaryColor,
+ title: Text("示例页面"),
+ elevation: 0,
+ automaticallyImplyLeading: false,
+ centerTitle: true,
+ ),
+ body: ListView.builder(
+ itemBuilder: (context, index) {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ width: MediaQuery.of(context).size.width,
+ color: index == 0
+ ? ref
+ .watch(themeProvider)
+ .themeColor
+ .pinColor()
+ : Colors.transparent,
+ padding: const EdgeInsets.symmetric(
+ horizontal: 15,
+ vertical: 8,
+ ),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment:
+ CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment:
+ MainAxisAlignment.start,
+ children: [
+ Expanded(
+ child: Row(
+ mainAxisSize: MainAxisSize.max,
+ mainAxisAlignment:
+ MainAxisAlignment.start,
+ children: [
+ Random().nextBool()
+ ? const SizedBox.shrink()
+ : SizedBox(
+ width: 15,
+ height: 15,
+ child:
+ CircularProgressIndicator(
+ strokeWidth: 2,
+ color: _primaryColor,
+ ),
+ ),
+ SizedBox(
+ width: Random().nextBool()
+ ? 0
+ : 5,
+ ),
+ Expanded(
+ child: Material(
+ color: Colors.transparent,
+ child: Text(
+ "示例名称",
+ maxLines: 1,
+ overflow:
+ TextOverflow.ellipsis,
+ style: TextStyle(
+ overflow: TextOverflow
+ .ellipsis,
+ color: ref
+ .watch(
+ themeProvider)
+ .themeColor
+ .titleColor(),
+ fontSize: 18,
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ Material(
+ color: Colors.transparent,
+ child: Text(
+ "上午10:00",
+ maxLines: 1,
+ style: TextStyle(
+ overflow: TextOverflow.ellipsis,
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .descColor(),
+ fontSize: 12,
+ ),
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ Row(
+ crossAxisAlignment:
+ CrossAxisAlignment.start,
+ children: [
+ Random().nextBool()
+ ? const Icon(
+ Icons.dnd_forwardslash,
+ size: 12,
+ color: Colors.red,
+ )
+ : const SizedBox.shrink(),
+ const SizedBox(
+ width: 5,
+ ),
+ Material(
+ color: Colors.transparent,
+ child: Text(
+ "10 1-12/2 * * *",
+ maxLines: 1,
+ style: TextStyle(
+ overflow: TextOverflow.ellipsis,
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .descColor(),
+ fontSize: 12,
+ ),
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ Material(
+ color: Colors.transparent,
+ child: Text(
+ "task raw post.js",
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ style: TextStyle(
+ overflow: TextOverflow.ellipsis,
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .descColor(),
+ fontSize: 12,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ const Divider(
+ height: 1,
+ indent: 15,
+ ),
+ ],
+ );
+ },
+ itemCount: 100,
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 20,
+ ),
+ ],
+ ),
+ ),
+ ),
+ const SizedBox(
+ height: 15,
+ ),
+ Container(
+ margin: const EdgeInsets.symmetric(
+ horizontal: 15,
+ ),
+ height: colorHeight + 20,
+ padding: const EdgeInsets.symmetric(vertical: 10),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(20),
+ ),
+ child: ListView.separated(
+ physics: BouncingScrollPhysics(),
+ padding: const EdgeInsets.symmetric(
+ horizontal: 15,
+ ),
+ scrollDirection: Axis.horizontal,
+ itemBuilder: (context, index) {
+ if (index == 0) {
+ return GestureDetector(
+ behavior: HitTestBehavior.opaque,
+ onTap: () {
+ pickColor();
+ },
+ child: SizedBox(
+ width: colorHeight,
+ height: colorHeight,
+ child: Stack(
+ children: [
+ Positioned(
+ child: Container(
+ width: smallColorHeight,
+ height: smallColorHeight,
+ decoration: BoxDecoration(
+ color: colors[0],
+ borderRadius:
+ BorderRadius.circular(smallColorHeight),
+ ),
+ ),
+ left: 0,
+ top: colorHeight / 4 - smallColorHeight / 2,
+ ),
+ Positioned(
+ child: Container(
+ width: smallColorHeight,
+ height: smallColorHeight,
+ decoration: BoxDecoration(
+ color: colors[1],
+ borderRadius:
+ BorderRadius.circular(smallColorHeight),
+ ),
+ ),
+ left: 0,
+ bottom: colorHeight / 4 - smallColorHeight / 2,
+ ),
+ Positioned(
+ child: Container(
+ width: smallColorHeight,
+ height: smallColorHeight,
+ decoration: BoxDecoration(
+ color: colors[2],
+ borderRadius:
+ BorderRadius.circular(smallColorHeight),
+ ),
+ ),
+ left: colorHeight / 2 - smallColorHeight / 2,
+ top: 0,
+ ),
+ Positioned(
+ child: Container(
+ width: smallColorHeight,
+ height: smallColorHeight,
+ decoration: BoxDecoration(
+ color: colors[3],
+ borderRadius:
+ BorderRadius.circular(smallColorHeight),
+ ),
+ ),
+ right: 0,
+ top: colorHeight / 4 - smallColorHeight / 2,
+ ),
+ Positioned(
+ child: Container(
+ width: smallColorHeight,
+ height: smallColorHeight,
+ decoration: BoxDecoration(
+ color: colors[4],
+ borderRadius:
+ BorderRadius.circular(smallColorHeight),
+ ),
+ ),
+ right: 0,
+ bottom: colorHeight / 4 - smallColorHeight / 2,
+ ),
+ Positioned(
+ child: Container(
+ width: smallColorHeight,
+ height: smallColorHeight,
+ decoration: BoxDecoration(
+ color: colors[5],
+ borderRadius:
+ BorderRadius.circular(smallColorHeight),
+ ),
+ ),
+ left: colorHeight / 2 - smallColorHeight / 2,
+ bottom: 0,
+ ),
+ Positioned(
+ child: Container(
+ width: smallColorHeight,
+ height: smallColorHeight,
+ decoration: BoxDecoration(
+ color: colors[6],
+ borderRadius:
+ BorderRadius.circular(smallColorHeight),
+ ),
+ ),
+ left: colorHeight / 2 - smallColorHeight / 2,
+ bottom: 0,
+ ),
+ Positioned(
+ child: Container(
+ width: smallColorHeight,
+ height: smallColorHeight,
+ decoration: BoxDecoration(
+ color: colors[7],
+ borderRadius:
+ BorderRadius.circular(smallColorHeight),
+ ),
+ ),
+ left: colorHeight / 2 - smallColorHeight / 2,
+ bottom: colorHeight / 2 - smallColorHeight / 2,
+ ),
+ ],
+ ),
+ ),
+ );
+ } else {
+ index = index - 1;
+
+ return GestureDetector(
+ onTap: () {
+ _primaryColor = colors[index];
+ setState(() {});
+ },
+ child: SizedBox(
+ width: colorHeight,
+ height: colorHeight,
+ child: Container(
+ decoration: BoxDecoration(
+ color: colors[index],
+ borderRadius: BorderRadius.circular(colorHeight),
+ ),
+ ),
+ ),
+ );
+ }
+ },
+ itemCount: colors.length + 1,
+ separatorBuilder: (BuildContext context, int index) {
+ return const SizedBox(
+ width: 15,
+ );
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ void pickColor() {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) {
+ return AlertDialog(
+ titlePadding: const EdgeInsets.all(0),
+ contentPadding: const EdgeInsets.all(0),
+ content: SingleChildScrollView(
+ child: ColorPicker(
+ pickerColor: _primaryColor,
+ onColorChanged: (color) {
+ _primaryColor = color;
+ setState(() {});
+ },
+ colorPickerWidth: 300,
+ pickerAreaHeightPercent: 0.7,
+ enableAlpha: false,
+ pickerAreaBorderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(2),
+ topRight: Radius.circular(2),
+ ),
+ hexInputBar: false,
+ ),
+ ),
+ );
+ },
+ );
+ }
+
+ void submit() {
+ ref.read(themeProvider).changePrimaryColor(_primaryColor);
+ Navigator.of(context).pop();
+ }
+}
diff --git a/lib/module/task/task_bean.dart b/lib/module/task/task_bean.dart
index 7d8ddf6..aa3c8b7 100644
--- a/lib/module/task/task_bean.dart
+++ b/lib/module/task/task_bean.dart
@@ -44,14 +44,14 @@ class TaskBean {
schedule = json['schedule'].toString();
saved = json['saved'];
sId = json.containsKey('_id') ? json['_id'].toString() : (json.containsKey('id') ? json['id'].toString() : "");
- created = json['created'];
+ created = int.tryParse(json['created'].toString());
status = json['status'];
timestamp = json['timestamp'].toString();
isSystem = json['isSystem'];
isDisabled = json['isDisabled'];
logPath = json['log_path'].toString();
isPinned = json['isPinned'];
- lastExecutionTime = json['last_execution_time'];
+ lastExecutionTime = int.tryParse(json['last_execution_time'].toString());
lastRunningTime = json['last_running_time'];
pid = json['pid'].toString();
} catch (e) {
diff --git a/lib/module/task/task_detail/task_detail_page.dart b/lib/module/task/task_detail/task_detail_page.dart
index bf27596..16df237 100644
--- a/lib/module/task/task_detail/task_detail_page.dart
+++ b/lib/module/task/task_detail/task_detail_page.dart
@@ -385,7 +385,7 @@ class _TaskDetailPageState extends ConsumerState {
child: Text(
"确定",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
),
),
onPressed: () async {
diff --git a/lib/module/task/task_page.dart b/lib/module/task/task_page.dart
index cf5c532..3698cc4 100644
--- a/lib/module/task/task_page.dart
+++ b/lib/module/task/task_page.dart
@@ -102,9 +102,17 @@ class _TaskPageState extends State {
TaskBean item = list[index];
if (_searchController.text.isEmpty ||
- (item.name?.toLowerCase().contains(_searchController.text.toLowerCase()) ?? false) ||
- (item.command?.toLowerCase().contains(_searchController.text.toLowerCase()) ?? false) ||
- (item.schedule?.contains(_searchController.text.toLowerCase()) ?? false)) {
+ (item.name
+ ?.toLowerCase()
+ .contains(_searchController.text.toLowerCase()) ??
+ false) ||
+ (item.command
+ ?.toLowerCase()
+ .contains(_searchController.text.toLowerCase()) ??
+ false) ||
+ (item.schedule
+ ?.contains(_searchController.text.toLowerCase()) ??
+ false)) {
return TaskItemCell(item, ref);
} else {
return const SizedBox.shrink();
@@ -175,10 +183,16 @@ class TaskItemCell extends StatelessWidget {
child: Text(
bean.status! == 1 ? "运行" : "停止运行",
),
- trailingIcon: bean.status! == 1 ? CupertinoIcons.memories : CupertinoIcons.stop_circle,
+ trailingIcon: bean.status! == 1
+ ? CupertinoIcons.memories
+ : CupertinoIcons.stop_circle,
onPressed: () {
Navigator.of(context).pop();
- startCron(context, ref);
+ if (bean.status! == 1) {
+ startCron(context, ref);
+ } else {
+ stopCron(context, ref);
+ }
},
),
QLCupertinoContextMenuAction(
@@ -193,7 +207,8 @@ class TaskItemCell extends StatelessWidget {
child: const Text("编辑"),
onPressed: () {
Navigator.of(context).pop();
- Navigator.of(context).pushNamed(Routes.routeAddTask, arguments: bean);
+ Navigator.of(context)
+ .pushNamed(Routes.routeAddTask, arguments: bean);
},
trailingIcon: CupertinoIcons.pencil_outline,
),
@@ -203,7 +218,9 @@ class TaskItemCell extends StatelessWidget {
Navigator.of(context).pop();
pinTask();
},
- trailingIcon: bean.isPinned! == 0 ? CupertinoIcons.pin : CupertinoIcons.pin_slash,
+ trailingIcon: bean.isPinned! == 0
+ ? CupertinoIcons.pin
+ : CupertinoIcons.pin_slash,
),
QLCupertinoContextMenuAction(
child: Text(bean.isDisabled! == 0 ? "禁用" : "启用"),
@@ -212,7 +229,9 @@ class TaskItemCell extends StatelessWidget {
enableTask();
},
isDestructiveAction: true,
- trailingIcon: bean.isDisabled! == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp,
+ trailingIcon: bean.isDisabled! == 0
+ ? Icons.dnd_forwardslash
+ : Icons.check_circle_outline_sharp,
),
QLCupertinoContextMenuAction(
child: const Text("删除"),
@@ -229,15 +248,17 @@ class TaskItemCell extends StatelessWidget {
return ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Container(
- color: isDark ? const Color(0xff333333) : Theme.of(context).scaffoldBackgroundColor,
+ color: isDark
+ ? const Color(0xff333333)
+ : Theme.of(context).scaffoldBackgroundColor,
padding: EdgeInsets.only(
left: 5,
right: 5,
top: 5,
bottom: isDark ? 5 : 20,
),
- child: ClipRRect(
- borderRadius: BorderRadius.circular(15),
+ child: SizedBox(
+ height: 200,
child: TaskDetailPage(
bean,
hideAppbar: true,
@@ -252,7 +273,9 @@ class TaskItemCell extends StatelessWidget {
children: [
Container(
width: MediaQuery.of(context).size.width,
- color: bean.isPinned == 1 ? ref.watch(themeProvider).themeColor.pinColor() : Colors.transparent,
+ color: bean.isPinned == 1
+ ? ref.watch(themeProvider).themeColor.pinColor()
+ : Colors.transparent,
padding: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 8,
@@ -265,39 +288,59 @@ class TaskItemCell extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
- Material(
- color: Colors.transparent,
- child: Text(
- bean.name ?? "",
- maxLines: 1,
- style: TextStyle(
- overflow: TextOverflow.ellipsis,
- color: ref.watch(themeProvider).themeColor.titleColor(),
- fontSize: 18,
- ),
- ),
- ),
- const SizedBox(
- width: 5,
- ),
- bean.status == 1
- ? const SizedBox.shrink()
- : const SizedBox(
- width: 15,
- height: 15,
- child: CircularProgressIndicator(
- strokeWidth: 2,
+ Expanded(
+ child: Row(
+ mainAxisSize: MainAxisSize.max,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ bean.status == 1
+ ? const SizedBox.shrink()
+ : SizedBox(
+ width: 15,
+ height: 15,
+ child: CircularProgressIndicator(
+ strokeWidth: 2,
+ color:
+ ref.watch(themeProvider).primaryColor,
+ ),
+ ),
+ SizedBox(
+ width: bean.status == 1 ? 0 : 5,
+ ),
+ Expanded(
+ child: Material(
+ color: Colors.transparent,
+ child: Text(
+ bean.name ?? "",
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ style: TextStyle(
+ overflow: TextOverflow.ellipsis,
+ color: ref
+ .watch(themeProvider)
+ .themeColor
+ .titleColor(),
+ fontSize: 18,
+ ),
+ ),
),
),
- const Spacer(),
+ ],
+ ),
+ ),
Material(
color: Colors.transparent,
child: Text(
- (bean.lastExecutionTime == null || bean.lastExecutionTime == 0) ? "-" : Utils.formatMessageTime(bean.lastExecutionTime!),
+ (bean.lastExecutionTime == null ||
+ bean.lastExecutionTime == 0)
+ ? "-"
+ : Utils.formatMessageTime(
+ bean.lastExecutionTime!),
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
- color: ref.watch(themeProvider).themeColor.descColor(),
+ color:
+ ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
),
@@ -310,21 +353,6 @@ class TaskItemCell extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Material(
- color: Colors.transparent,
- child: Text(
- bean.schedule ?? "",
- maxLines: 1,
- style: TextStyle(
- overflow: TextOverflow.ellipsis,
- color: ref.watch(themeProvider).themeColor.descColor(),
- fontSize: 12,
- ),
- ),
- ),
- const SizedBox(
- width: 5,
- ),
bean.isDisabled == 1
? const Icon(
Icons.dnd_forwardslash,
@@ -332,6 +360,22 @@ class TaskItemCell extends StatelessWidget {
color: Colors.red,
)
: const SizedBox.shrink(),
+ const SizedBox(
+ width: 5,
+ ),
+ Material(
+ color: Colors.transparent,
+ child: Text(
+ bean.schedule ?? "",
+ maxLines: 1,
+ style: TextStyle(
+ overflow: TextOverflow.ellipsis,
+ color:
+ ref.watch(themeProvider).themeColor.descColor(),
+ fontSize: 12,
+ ),
+ ),
+ ),
],
),
const SizedBox(
@@ -433,7 +477,7 @@ class TaskItemCell extends StatelessWidget {
child: Text(
"确定",
style: TextStyle(
- color: primaryColor,
+ color: ref.watch(themeProvider).primaryColor,
),
),
onPressed: () {
diff --git a/lib/module/task/task_viewmodel.dart b/lib/module/task/task_viewmodel.dart
index 22104fb..261e1c0 100644
--- a/lib/module/task/task_viewmodel.dart
+++ b/lib/module/task/task_viewmodel.dart
@@ -48,6 +48,7 @@ class TaskViewModel extends BaseViewModel {
HttpResponse result = await Api.startTasks([cron]);
if (result.success) {
list.firstWhere((element) => element.sId == cron).status = 0;
+ sortList();
notifyListeners();
} else {
failToast(result.message, notify: true);
@@ -58,6 +59,7 @@ class TaskViewModel extends BaseViewModel {
HttpResponse result = await Api.stopTasks([cron]);
if (result.success) {
list.firstWhere((element) => element.sId == cron).status = 1;
+ sortList();
notifyListeners();
} else {
failToast(result.message, notify: true);
diff --git a/lib/utils/update_utils.dart b/lib/utils/update_utils.dart
new file mode 100644
index 0000000..2cd9f98
--- /dev/null
+++ b/lib/utils/update_utils.dart
@@ -0,0 +1,395 @@
+import 'dart:math';
+
+import 'package:dio/dio.dart';
+import 'package:flutter/material.dart';
+import 'package:package_info_plus/package_info_plus.dart';
+import 'package:qinglong_app/base/http/url.dart';
+import 'package:qinglong_app/utils/extension.dart';
+import 'package:url_launcher/url_launcher.dart';
+
+import '../main.dart';
+
+/// @author NewTab
+
+class UpdateUtils {
+ Future checkUpdate([bool remind = false]) async {
+ try {
+ PackageInfo packageInfo = await PackageInfo.fromPlatform();
+
+ String version = packageInfo.version;
+ String url = Url.checkUpdateUrl;
+ Dio dio = Dio(BaseOptions(
+ connectTimeout: 50000,
+ receiveTimeout: 50000,
+ sendTimeout: 50000,
+ ));
+ var response = await dio.get(url);
+ if (response.statusCode == 200) {
+ if (version == response.data as String) {
+ return null;
+ }
+ return response.data as String;
+ }
+ } on DioError catch (e) {
+ if (remind) {
+ "无法连接到github服务器,版本更新检测失败".toast();
+ }
+ logger.e(e);
+ return null;
+ }
+ }
+
+ static void launchURL(String version) async {
+ try {
+ await launch("https://github.com/qinglong-app/qinglong_app/releases/download/v$version/app-release-v$version.apk");
+ } catch (e) {
+ logger.e(e);
+ }
+ }
+}
+
+///版本更新加提示框
+class UpdateDialog {
+ bool _isShowing = false;
+ late BuildContext _context;
+ late UpdateWidget _widget;
+
+ UpdateDialog(BuildContext context,
+ {double width = 0.0,
+ required String title,
+ required String updateContent,
+ required VoidCallback onUpdate,
+ double titleTextSize = 16.0,
+ double contentTextSize = 14.0,
+ double buttonTextSize = 14.0,
+ double progress = -1.0,
+ Color progressBackgroundColor = const Color(0xFFFFCDD2),
+ Image? topImage,
+ double extraHeight = 5.0,
+ double radius = 4.0,
+ Color themeColor = Colors.red,
+ bool enableIgnore = false,
+ VoidCallback? onIgnore,
+ bool isForce = false,
+ String? updateButtonText,
+ String? ignoreButtonText,
+ VoidCallback? onClose}) {
+ _context = context;
+ _widget = UpdateWidget(
+ width: width,
+ title: title,
+ updateContent: updateContent,
+ onUpdate: onUpdate,
+ titleTextSize: titleTextSize,
+ contentTextSize: contentTextSize,
+ buttonTextSize: buttonTextSize,
+ progress: progress,
+ topImage: topImage,
+ extraHeight: extraHeight,
+ radius: radius,
+ themeColor: themeColor,
+ progressBackgroundColor: progressBackgroundColor,
+ enableIgnore: enableIgnore,
+ onIgnore: onIgnore,
+ isForce: isForce,
+ updateButtonText: updateButtonText ?? '更新',
+ ignoreButtonText: ignoreButtonText ?? '忽略此版本',
+ onClose: onClose ?? () => dismiss());
+ }
+
+ /// 显示弹窗
+ Future show() {
+ try {
+ if (isShowing()) {
+ return Future.value(false);
+ }
+ showDialog(
+ context: _context,
+ barrierDismissible: false,
+ builder: (BuildContext context) {
+ return WillPopScope(onWillPop: () => Future.value(false), child: _widget);
+ });
+ _isShowing = true;
+ return Future.value(true);
+ } catch (err) {
+ _isShowing = false;
+ return Future.value(false);
+ }
+ }
+
+ /// 隐藏弹窗
+ Future dismiss() {
+ try {
+ if (_isShowing) {
+ _isShowing = false;
+ Navigator.pop(_context);
+ return Future.value(true);
+ } else {
+ return Future.value(false);
+ }
+ } catch (err) {
+ return Future.value(false);
+ }
+ }
+
+ /// 是否显示
+ bool isShowing() {
+ return _isShowing;
+ }
+
+ /// 更新进度
+ void update(double progress) {
+ if (isShowing()) {
+ _widget.update(progress);
+ }
+ }
+
+ /// 显示版本更新提示框
+ static UpdateDialog showUpdate(BuildContext context,
+ {double width = 0.0,
+ required String title,
+ required String updateContent,
+ required VoidCallback onUpdate,
+ double titleTextSize = 16.0,
+ double contentTextSize = 14.0,
+ double buttonTextSize = 14.0,
+ double progress = -1.0,
+ Color progressBackgroundColor = const Color(0xFFFFCDD2),
+ Image? topImage,
+ double extraHeight = 5.0,
+ double radius = 4.0,
+ Color themeColor = Colors.red,
+ bool enableIgnore = false,
+ VoidCallback? onIgnore,
+ String? updateButtonText,
+ String? ignoreButtonText,
+ bool isForce = false}) {
+ final UpdateDialog dialog = UpdateDialog(context,
+ width: width,
+ title: title,
+ updateContent: updateContent,
+ onUpdate: onUpdate,
+ titleTextSize: titleTextSize,
+ contentTextSize: contentTextSize,
+ buttonTextSize: buttonTextSize,
+ progress: progress,
+ topImage: topImage,
+ extraHeight: extraHeight,
+ radius: radius,
+ themeColor: themeColor,
+ progressBackgroundColor: progressBackgroundColor,
+ enableIgnore: enableIgnore,
+ isForce: isForce,
+ updateButtonText: updateButtonText,
+ ignoreButtonText: ignoreButtonText,
+ onIgnore: onIgnore);
+ dialog.show();
+ return dialog;
+ }
+}
+
+// ignore: must_be_immutable
+class UpdateWidget extends StatefulWidget {
+ /// 对话框的宽度
+ final double width;
+
+ /// 升级标题
+ final String title;
+
+ /// 更新内容
+ final String updateContent;
+
+ /// 标题文字的大小
+ final double titleTextSize;
+
+ /// 更新文字内容的大小
+ final double contentTextSize;
+
+ /// 按钮文字的大小
+ final double buttonTextSize;
+
+ /// 顶部图片
+ final Widget? topImage;
+
+ /// 拓展高度(适配顶部图片高度不一致的情况)
+ final double extraHeight;
+
+ /// 边框圆角大小
+ final double radius;
+
+ /// 主题颜色
+ final Color themeColor;
+
+ /// 更新事件
+ final VoidCallback onUpdate;
+
+ /// 可忽略更新
+ final bool enableIgnore;
+
+ /// 更新事件
+ final VoidCallback? onIgnore;
+
+ double progress;
+
+ /// 进度条的背景颜色
+ final Color progressBackgroundColor;
+
+ /// 更新事件
+ final VoidCallback? onClose;
+
+ /// 是否是强制更新
+ final bool isForce;
+
+ /// 更新按钮内容
+ final String updateButtonText;
+
+ /// 忽略按钮内容
+ final String ignoreButtonText;
+
+ UpdateWidget(
+ {Key? key,
+ this.width = 0.0,
+ required this.title,
+ required this.updateContent,
+ required this.onUpdate,
+ this.titleTextSize = 16.0,
+ this.contentTextSize = 14.0,
+ this.buttonTextSize = 14.0,
+ this.progress = -1.0,
+ this.progressBackgroundColor = const Color(0xFFFFCDD2),
+ this.topImage,
+ this.extraHeight = 5.0,
+ this.radius = 4.0,
+ this.themeColor = Colors.red,
+ this.enableIgnore = false,
+ this.onIgnore,
+ this.isForce = false,
+ this.updateButtonText = '更新',
+ this.ignoreButtonText = '忽略此版本',
+ this.onClose})
+ : super(key: key);
+
+ final _UpdateWidgetState _state = _UpdateWidgetState();
+
+ void update(double progress) {
+ _state.update(progress);
+ }
+
+ @override
+ _UpdateWidgetState createState() => _state;
+}
+
+class _UpdateWidgetState extends State {
+ void update(double progress) {
+ if (!mounted) {
+ return;
+ }
+ setState(() {
+ widget.progress = progress;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final double dialogWidth = widget.width <= 0 ? getFitWidth(context) * 0.618 : widget.width;
+ return Material(
+ type: MaterialType.transparency,
+ child: SizedBox(
+ width: dialogWidth,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SizedBox(
+ width: dialogWidth,
+ child: widget.topImage ?? Image.asset('assets/images/update_bg_app_top.png', fit: BoxFit.fill),
+ ),
+ Container(
+ width: dialogWidth,
+ alignment: Alignment.center,
+ padding: const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 8),
+ decoration: ShapeDecoration(
+ color: Colors.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.only(bottomLeft: Radius.circular(widget.radius), bottomRight: Radius.circular(widget.radius)),
+ ),
+ ),
+ child: SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ padding: EdgeInsets.only(top: widget.extraHeight),
+ child: Text(widget.title, style: TextStyle(fontSize: widget.titleTextSize, color: Colors.black)),
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 10),
+ child: Text(widget.updateContent, style: TextStyle(fontSize: widget.contentTextSize, color: const Color(0xFF666666))),
+ ),
+ Column(children: [
+ FractionallySizedBox(
+ widthFactor: 1,
+ child: ElevatedButton(
+ style: ButtonStyle(
+ tapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ textStyle: MaterialStateProperty.all(TextStyle(fontSize: widget.buttonTextSize)),
+ foregroundColor: MaterialStateProperty.all(Colors.white),
+ shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(5))),
+ elevation: MaterialStateProperty.all(0),
+ backgroundColor: MaterialStateProperty.all(widget.themeColor),
+ ),
+ child: Text(widget.updateButtonText),
+ onPressed: widget.onUpdate,
+ ),
+ ),
+ if (widget.enableIgnore && widget.onIgnore != null)
+ FractionallySizedBox(
+ widthFactor: 1,
+ child: TextButton(
+ style: ButtonStyle(
+ tapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ textStyle: MaterialStateProperty.all(TextStyle(fontSize: widget.buttonTextSize)),
+ foregroundColor: MaterialStateProperty.all(const Color(0xFF666666)),
+ shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(5))),
+ ),
+ child: Text(widget.ignoreButtonText),
+ onPressed: widget.onIgnore,
+ ))
+ else
+ const SizedBox()
+ ]),
+ ],
+ )),
+ ),
+ if (!widget.isForce)
+ Column(children: [
+ const SizedBox(width: 1.5, height: 50, child: DecoratedBox(decoration: BoxDecoration(color: Colors.white))),
+ IconButton(
+ iconSize: 30,
+ constraints: const BoxConstraints(maxHeight: 30, maxWidth: 30),
+ padding: EdgeInsets.zero,
+ icon: Image.asset(
+ 'assets/images/update_ic_close.png',
+ ),
+ onPressed: widget.onClose,
+ )
+ ])
+ else
+ const SizedBox()
+ ],
+ ),
+ ));
+ }
+
+ double getFitWidth(BuildContext context) {
+ return min(getScreenHeight(context), getScreenWidth(context));
+ }
+
+ double getScreenHeight(BuildContext context) {
+ return MediaQuery.of(context).size.height;
+ }
+
+ double getScreenWidth(BuildContext context) {
+ return MediaQuery.of(context).size.width;
+ }
+}
diff --git a/pubspec.lock b/pubspec.lock
index 32253ba..f722a25 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -5,245 +5,245 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "22.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.7.2"
archive:
dependency: transitive
description:
name: archive
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "3.1.8"
+ version: "3.1.9"
args:
dependency: transitive
description:
name: args
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
async:
dependency: transitive
description:
name: async
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
back_button_interceptor:
dependency: "direct main"
description:
name: back_button_interceptor
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "5.0.2"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
build:
dependency: transitive
description:
name: build
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
build_config:
dependency: transitive
description:
name: build_config
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
build_daemon:
dependency: transitive
description:
name: build_daemon
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
build_runner:
dependency: "direct dev"
description:
name: build_runner
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.7"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "7.2.3"
built_collection:
dependency: transitive
description:
name: built_collection
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "5.1.1"
built_value:
dependency: transitive
description:
name: built_value
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "8.1.4"
change_app_package_name:
dependency: "direct dev"
description:
name: change_app_package_name
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
characters:
dependency: transitive
description:
name: characters
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
charcode:
dependency: transitive
description:
name: charcode
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
cli_util:
dependency: transitive
description:
name: cli_util
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.3.5"
clock:
dependency: transitive
description:
name: clock
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
code_builder:
dependency: transitive
description:
name: code_builder
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
collection:
dependency: transitive
description:
name: collection
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0"
convert:
dependency: transitive
description:
name: convert
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
crypto:
dependency: transitive
description:
name: crypto
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
dart_style:
dependency: transitive
description:
name: dart_style
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
dio:
dependency: "direct main"
description:
name: dio
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "4.0.4"
dio_log:
dependency: "direct main"
description:
name: dio_log
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
drag_and_drop_lists:
dependency: "direct main"
description:
name: drag_and_drop_lists
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.3.2+2"
fake_async:
dependency: transitive
description:
name: fake_async
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
ffi:
dependency: transitive
description:
name: ffi
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
file:
dependency: transitive
description:
name: file
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
fixnum:
dependency: transitive
description:
name: fixnum
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
flip_card:
dependency: "direct main"
description:
name: flip_card
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.6.0"
flutter:
@@ -255,49 +255,56 @@ packages:
dependency: "direct dev"
description:
name: flutter_app_name
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
+ flutter_colorpicker:
+ dependency: "direct main"
+ description:
+ name: flutter_colorpicker
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.3"
flutter_highlight:
dependency: "direct main"
description:
name: flutter_highlight
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.7.0"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.9.2"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
flutter_native_splash:
dependency: "direct dev"
description:
name: flutter_native_splash
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.3.3"
flutter_riverpod:
dependency: "direct main"
description:
name: flutter_riverpod
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
flutter_slidable:
dependency: "direct main"
description:
name: flutter_slidable
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
flutter_test:
@@ -314,371 +321,371 @@ packages:
dependency: "direct main"
description:
name: fluttertoast
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "8.0.8"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
get_it:
dependency: "direct main"
description:
name: get_it
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "7.2.0"
glob:
dependency: transitive
description:
name: glob
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
graphs:
dependency: transitive
description:
name: graphs
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
highlight:
dependency: transitive
description:
name: highlight
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.7.0"
http:
dependency: transitive
description:
name: http
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.13.4"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
http_parser:
dependency: transitive
description:
name: http_parser
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
image:
dependency: transitive
description:
name: image
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
intl:
dependency: "direct main"
description:
name: intl
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.17.0"
io:
dependency: transitive
description:
name: io
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
js:
dependency: transitive
description:
name: js
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.6.3"
json_annotation:
dependency: transitive
description:
name: json_annotation
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "4.4.0"
json_conversion:
dependency: "direct dev"
description:
name: json_conversion
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4"
json_conversion_annotation:
dependency: "direct main"
description:
name: json_conversion_annotation
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4"
lints:
dependency: transitive
description:
name: lints
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
logger:
dependency: "direct main"
description:
name: logger
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
logging:
dependency: transitive
description:
name: logging
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
matcher:
dependency: transitive
description:
name: matcher
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
meta:
dependency: transitive
description:
name: meta
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
mime:
dependency: transitive
description:
name: mime
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
move_to_background:
dependency: "direct main"
description:
name: move_to_background
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
package_config:
dependency: transitive
description:
name: package_config
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
package_info_plus:
dependency: "direct main"
description:
name: package_info_plus
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
package_info_plus_linux:
dependency: transitive
description:
name: package_info_plus_linux
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
package_info_plus_macos:
dependency: transitive
description:
name: package_info_plus_macos
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
package_info_plus_web:
dependency: transitive
description:
name: package_info_plus_web
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
package_info_plus_windows:
dependency: transitive
description:
name: package_info_plus_windows
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
path:
dependency: transitive
description:
name: path
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
pedantic:
dependency: transitive
description:
name: pedantic
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.11.1"
petitparser:
dependency: transitive
description:
name: petitparser
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "4.4.0"
platform:
dependency: transitive
description:
name: platform
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
pool:
dependency: transitive
description:
name: pool
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.5.0"
process:
dependency: transitive
description:
name: process
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "4.2.4"
pub_semver:
dependency: transitive
description:
name: pub_semver
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
riverpod:
dependency: transitive
description:
name: riverpod
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.12"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.10"
shared_preferences_ios:
dependency: transitive
description:
name: shared_preferences_ios
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
shelf:
dependency: transitive
description:
name: shelf
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
sky_engine:
@@ -690,196 +697,196 @@ packages:
dependency: transitive
description:
name: source_gen
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
source_span:
dependency: transitive
description:
name: source_span
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0"
state_notifier:
dependency: transitive
description:
name: state_notifier
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.7.2+1"
stream_channel:
dependency: transitive
description:
name: stream_channel
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
synchronized:
dependency: "direct main"
description:
name: synchronized
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
test_api:
dependency: transitive
description:
name: test_api
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.4.3"
timing:
dependency: transitive
description:
name: timing
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
typed_data:
dependency: transitive
description:
name: typed_data
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
universal_io:
dependency: transitive
description:
name: universal_io
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "6.0.18"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "6.0.14"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "6.0.14"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
vector_math:
dependency: transitive
description:
name: vector_math
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
watcher:
dependency: transitive
description:
name: watcher
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
win32:
dependency: transitive
description:
name: win32
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.3.6"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
xml:
dependency: transitive
description:
name: xml
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "5.3.1"
yaml:
dependency: transitive
description:
name: yaml
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
sdks:
diff --git a/pubspec.yaml b/pubspec.yaml
index 3df434f..6896455 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,7 +1,7 @@
name: qinglong_app
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
-version: 1.0.3+4
+version: 1.0.4+5
environment:
sdk: ">=2.15.1 <3.0.0"
@@ -31,6 +31,7 @@ dependencies:
flip_card: ^0.6.0
package_info_plus: ^1.3.0
url_launcher: ^6.0.18
+ flutter_colorpicker: ^1.0.3
dev_dependencies:
flutter_native_splash: ^1.3.3
diff --git a/test/widget_test.dart b/test/widget_test.dart
index fd3f115..baa5890 100644
--- a/test/widget_test.dart
+++ b/test/widget_test.dart
@@ -6,8 +6,5 @@
// tree, read text, and verify that the values of widget properties are correct.
void main() {
- String time = "Wed Jan 12 2022 20:33:39 GMT+0800 (中国标准时间)";
- var result = DateTime.tryParse(time);
- print(result);
}
diff --git a/version b/version
new file mode 100644
index 0000000..a6a3a43
--- /dev/null
+++ b/version
@@ -0,0 +1 @@
+1.0.4
\ No newline at end of file