diff --git a/assets/images/chun.png b/assets/images/chun.png deleted file mode 100644 index e49600e..0000000 Binary files a/assets/images/chun.png and /dev/null differ diff --git a/assets/images/dark.png b/assets/images/dark.png new file mode 100644 index 0000000..f48d0dd Binary files /dev/null and b/assets/images/dark.png differ diff --git a/assets/images/faceid.png b/assets/images/faceid.png new file mode 100644 index 0000000..6485236 Binary files /dev/null and b/assets/images/faceid.png differ diff --git a/assets/images/figure.png b/assets/images/figure.png new file mode 100644 index 0000000..a44cdb1 Binary files /dev/null and b/assets/images/figure.png differ diff --git a/assets/images/icon_a.png b/assets/images/icon_a.png new file mode 100644 index 0000000..6f678dd Binary files /dev/null and b/assets/images/icon_a.png differ diff --git a/assets/images/icon_about.png b/assets/images/icon_about.png new file mode 100644 index 0000000..ce3d4a5 Binary files /dev/null and b/assets/images/icon_about.png differ diff --git a/assets/images/icon_app_set.png b/assets/images/icon_app_set.png new file mode 100644 index 0000000..2c70174 Binary files /dev/null and b/assets/images/icon_app_set.png differ diff --git a/assets/images/icon_b.png b/assets/images/icon_b.png new file mode 100644 index 0000000..e8401eb Binary files /dev/null and b/assets/images/icon_b.png differ diff --git a/assets/images/icon_check.png b/assets/images/icon_check.png new file mode 100644 index 0000000..bd07524 Binary files /dev/null and b/assets/images/icon_check.png differ diff --git a/assets/images/icon_cron.png b/assets/images/icon_cron.png new file mode 100644 index 0000000..a03802f Binary files /dev/null and b/assets/images/icon_cron.png differ diff --git a/assets/images/icon_cron_checked.png b/assets/images/icon_cron_checked.png new file mode 100644 index 0000000..705f9b3 Binary files /dev/null and b/assets/images/icon_cron_checked.png differ diff --git a/assets/images/icon_d.png b/assets/images/icon_d.png new file mode 100644 index 0000000..3c2af27 Binary files /dev/null and b/assets/images/icon_d.png differ diff --git a/assets/images/icon_default_user.png b/assets/images/icon_default_user.png new file mode 100644 index 0000000..09a62ac Binary files /dev/null and b/assets/images/icon_default_user.png differ diff --git a/assets/images/icon_disabled.png b/assets/images/icon_disabled.png new file mode 100644 index 0000000..2e06765 Binary files /dev/null and b/assets/images/icon_disabled.png differ diff --git a/assets/images/icon_enable.png b/assets/images/icon_enable.png new file mode 100644 index 0000000..2ac6a5b Binary files /dev/null and b/assets/images/icon_enable.png differ diff --git a/assets/images/icon_env.png b/assets/images/icon_env.png new file mode 100644 index 0000000..66e1dbe Binary files /dev/null and b/assets/images/icon_env.png differ diff --git a/assets/images/icon_env_checked.png b/assets/images/icon_env_checked.png new file mode 100644 index 0000000..1ece568 Binary files /dev/null and b/assets/images/icon_env_checked.png differ diff --git a/assets/images/icon_fail.png b/assets/images/icon_fail.png new file mode 100644 index 0000000..e8c79ff Binary files /dev/null and b/assets/images/icon_fail.png differ diff --git a/assets/images/icon_file.png b/assets/images/icon_file.png new file mode 100644 index 0000000..ad94f24 Binary files /dev/null and b/assets/images/icon_file.png differ diff --git a/assets/images/icon_file_checked.png b/assets/images/icon_file_checked.png new file mode 100644 index 0000000..54f39de Binary files /dev/null and b/assets/images/icon_file_checked.png differ diff --git a/assets/images/icon_history.png b/assets/images/icon_history.png new file mode 100644 index 0000000..c89227a Binary files /dev/null and b/assets/images/icon_history.png differ diff --git a/assets/images/icon_idle.png b/assets/images/icon_idle.png new file mode 100644 index 0000000..3a812b3 Binary files /dev/null and b/assets/images/icon_idle.png differ diff --git a/assets/images/icon_install_fail.png b/assets/images/icon_install_fail.png new file mode 100644 index 0000000..07b75e8 Binary files /dev/null and b/assets/images/icon_install_fail.png differ diff --git a/assets/images/icon_install_success.png b/assets/images/icon_install_success.png new file mode 100644 index 0000000..4beab6a Binary files /dev/null and b/assets/images/icon_install_success.png differ diff --git a/assets/images/icon_login_icon.png b/assets/images/icon_login_icon.png new file mode 100644 index 0000000..9740da1 Binary files /dev/null and b/assets/images/icon_login_icon.png differ diff --git a/assets/images/icon_other.png b/assets/images/icon_other.png new file mode 100644 index 0000000..94c7b06 Binary files /dev/null and b/assets/images/icon_other.png differ diff --git a/assets/images/icon_other_bg.png b/assets/images/icon_other_bg.png new file mode 100644 index 0000000..4f92b04 Binary files /dev/null and b/assets/images/icon_other_bg.png differ diff --git a/assets/images/icon_other_checked.png b/assets/images/icon_other_checked.png new file mode 100644 index 0000000..58282f7 Binary files /dev/null and b/assets/images/icon_other_checked.png differ diff --git a/assets/images/icon_right.png b/assets/images/icon_right.png new file mode 100644 index 0000000..d2482dd Binary files /dev/null and b/assets/images/icon_right.png differ diff --git a/assets/images/icon_running.png b/assets/images/icon_running.png new file mode 100644 index 0000000..3b26804 Binary files /dev/null and b/assets/images/icon_running.png differ diff --git a/assets/images/icon_s.png b/assets/images/icon_s.png new file mode 100644 index 0000000..b9b5ff0 Binary files /dev/null and b/assets/images/icon_s.png differ diff --git a/assets/images/icon_safety.png b/assets/images/icon_safety.png new file mode 100644 index 0000000..96a115e Binary files /dev/null and b/assets/images/icon_safety.png differ diff --git a/assets/images/icon_search.png b/assets/images/icon_search.png new file mode 100644 index 0000000..f4a9d00 Binary files /dev/null and b/assets/images/icon_search.png differ diff --git a/assets/images/icon_setting.png b/assets/images/icon_setting.png new file mode 100644 index 0000000..bea3c72 Binary files /dev/null and b/assets/images/icon_setting.png differ diff --git a/assets/images/icon_subsctibe.png b/assets/images/icon_subsctibe.png new file mode 100644 index 0000000..d8fe88b Binary files /dev/null and b/assets/images/icon_subsctibe.png differ diff --git a/assets/images/icon_success.png b/assets/images/icon_success.png new file mode 100644 index 0000000..f3b9989 Binary files /dev/null and b/assets/images/icon_success.png differ diff --git a/assets/images/icon_task_disable.png b/assets/images/icon_task_disable.png new file mode 100644 index 0000000..cf64717 Binary files /dev/null and b/assets/images/icon_task_disable.png differ diff --git a/assets/images/icon_task_log.png b/assets/images/icon_task_log.png new file mode 100644 index 0000000..9b83895 Binary files /dev/null and b/assets/images/icon_task_log.png differ diff --git a/assets/images/icon_uncheck.png b/assets/images/icon_uncheck.png new file mode 100644 index 0000000..028c457 Binary files /dev/null and b/assets/images/icon_uncheck.png differ diff --git a/assets/images/icon_vip_bg.png b/assets/images/icon_vip_bg.png new file mode 100644 index 0000000..7173c03 Binary files /dev/null and b/assets/images/icon_vip_bg.png differ diff --git a/assets/images/icon_vip_bg_check.png b/assets/images/icon_vip_bg_check.png new file mode 100644 index 0000000..e562e12 Binary files /dev/null and b/assets/images/icon_vip_bg_check.png differ diff --git a/assets/images/kuai.png b/assets/images/kuai.png deleted file mode 100644 index a599fae..0000000 Binary files a/assets/images/kuai.png and /dev/null differ diff --git a/assets/images/le.png b/assets/images/le.png deleted file mode 100644 index 0d56eaa..0000000 Binary files a/assets/images/le.png and /dev/null differ diff --git a/assets/images/light.png b/assets/images/light.png new file mode 100644 index 0000000..669384e Binary files /dev/null and b/assets/images/light.png differ diff --git a/assets/images/normal.png b/assets/images/normal.png new file mode 100644 index 0000000..52ac4b5 Binary files /dev/null and b/assets/images/normal.png differ diff --git a/assets/images/ql.png b/assets/images/ql.png index 749ac34..09bc684 100644 Binary files a/assets/images/ql.png and b/assets/images/ql.png differ diff --git a/assets/images/ql_white.png b/assets/images/ql_white.png index f4688c7..09bc684 100644 Binary files a/assets/images/ql_white.png and b/assets/images/ql_white.png differ diff --git a/assets/images/svip.png b/assets/images/svip.png new file mode 100644 index 0000000..2590eb2 Binary files /dev/null and b/assets/images/svip.png differ diff --git a/assets/images/svip_logo.png b/assets/images/svip_logo.png new file mode 100644 index 0000000..bfb314f Binary files /dev/null and b/assets/images/svip_logo.png differ diff --git a/assets/images/vip.png b/assets/images/vip.png new file mode 100644 index 0000000..e2e98ff Binary files /dev/null and b/assets/images/vip.png differ diff --git a/assets/images/vip_logo.png b/assets/images/vip_logo.png new file mode 100644 index 0000000..d8c89f9 Binary files /dev/null and b/assets/images/vip_logo.png differ diff --git a/assets/images/xin.png b/assets/images/xin.png deleted file mode 100644 index ddf7be0..0000000 Binary files a/assets/images/xin.png and /dev/null differ diff --git a/lib/base/routes.dart b/lib/base/routes.dart index 2c9111a..d20b04a 100644 --- a/lib/base/routes.dart +++ b/lib/base/routes.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:qinglong_app/module/change_account_page.dart'; import 'package:qinglong_app/module/config/config_edit_page.dart'; import 'package:qinglong_app/module/env/add_env_page.dart'; import 'package:qinglong_app/module/env/env_bean.dart'; @@ -41,6 +42,7 @@ class Routes { static const String routeUpdatePassword = "/updatePassword"; static const String routeAbout = "/about"; static const String routeTheme = "/theme"; + static const String routeChangeAccount = "/changeAccount"; static Route? generateRoute(RouteSettings settings) { switch (settings.name) { @@ -55,7 +57,10 @@ class Routes { } else { return MaterialPageRoute(builder: (context) => const LoginPage()); } - + case routeChangeAccount: + return CupertinoPageRoute( + builder: (context) => const ChangeAccountPage(), + ); case routeAddTask: if (settings.arguments != null) { return CupertinoPageRoute( @@ -66,8 +71,7 @@ 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( diff --git a/lib/base/theme.dart b/lib/base/theme.dart index c95b8aa..1800635 100644 --- a/lib/base/theme.dart +++ b/lib/base/theme.dart @@ -69,7 +69,7 @@ class ThemeViewModel extends ChangeNotifier { secondary: _primaryColor, primary: _primaryColor, ), - scaffoldBackgroundColor: const Color(0xfff5f5f5), + scaffoldBackgroundColor: const Color(0xffffffff), inputDecorationTheme: InputDecorationTheme( labelStyle: TextStyle( color: _primaryColor, @@ -223,6 +223,8 @@ abstract class ThemeColors { Color tabBarColor(); + Color blackAndWhite(); + Color pinColor(); Color buttonBgColor(); @@ -241,6 +243,11 @@ class LightThemeColors extends ThemeColors { return const Color(0xffF7F7F7); } + @override + Color blackAndWhite() { + return Colors.white; + } + @override Map codeEditorTheme() { return qinglongLightTheme; @@ -288,6 +295,11 @@ class DartThemeColors extends ThemeColors { return qinglongDarkTheme; } + @override + Color blackAndWhite() { + return Colors.black; + } + @override Color descColor() { return const Color(0xff999999); diff --git a/lib/base/ui/search_cell.dart b/lib/base/ui/search_cell.dart new file mode 100644 index 0000000..bc4aacc --- /dev/null +++ b/lib/base/ui/search_cell.dart @@ -0,0 +1,69 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../theme.dart'; + +class SearchCell extends ConsumerStatefulWidget { + final TextEditingController controller; + + const SearchCell({ + Key? key, + required this.controller, + }) : super(key: key); + + @override + ConsumerState createState() => _SearchCellState(); +} + +class _SearchCellState extends ConsumerState { + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return CupertinoSearchTextField( + decoration: BoxDecoration( + color: ref.watch(themeProvider).themeColor.blackAndWhite(), + border: Border.all(width: 1, color: const Color(0xffC0C4CC)), + borderRadius: BorderRadius.circular( + 7, + ), + ), + onSuffixTap: () { + widget.controller.text = ""; + setState(() { + + }); + }, + controller: widget.controller, + padding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 5, + ), + suffixInsets: const EdgeInsets.only( + right: 15, + ), + prefixIcon: Image.asset( + "assets/images/icon_search.png", + width: 18, + fit: BoxFit.cover, + ), + prefixInsets: const EdgeInsets.only( + left: 10, + top: 2, + ), + placeholderStyle: TextStyle( + fontSize: 14, + color: ref.watch(themeProvider).themeColor.descColor(), + ), + style: const TextStyle( + fontSize: 16, + ), + placeholder: "请输入内容", + ); + } +} diff --git a/lib/module/change_account_page.dart b/lib/module/change_account_page.dart new file mode 100644 index 0000000..77343c6 --- /dev/null +++ b/lib/module/change_account_page.dart @@ -0,0 +1,316 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:qinglong_app/base/http/api.dart'; +import 'package:qinglong_app/base/http/http.dart'; +import 'package:qinglong_app/base/ql_app_bar.dart'; +import 'package:qinglong_app/base/routes.dart'; +import 'package:qinglong_app/base/theme.dart'; +import 'package:qinglong_app/base/userinfo_viewmodel.dart'; +import 'package:qinglong_app/utils/extension.dart'; +import 'package:qinglong_app/utils/login_helper.dart'; + +import '../../main.dart'; + +class ChangeAccountPage extends ConsumerStatefulWidget { + const ChangeAccountPage({Key? key}) : super(key: key); + + @override + _ChangeAccountPageState createState() => _ChangeAccountPageState(); +} + +class _ChangeAccountPageState extends ConsumerState { + String isLoginingHost = ""; + String preHost = ""; + + @override + void initState() { + super.initState(); + preHost = getIt().historyAccounts.first.host ?? ""; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: QlAppBar( + canBack: true, + title: "切换账号", + ), + body: SingleChildScrollView( + child: SizedBox( + width: MediaQuery.of(context).size.width, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: MediaQuery.of(context).size.height / 10, + ), + Text( + "轻触账号以切换登录", + style: TextStyle( + color: ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 22, + ), + ), + const SizedBox( + height: 30, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + if (index == getIt().historyAccounts.length) { + return addAccount(); + } + return ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Container( + color: ref.watch(themeProvider).themeColor.settingBordorColor(), + child: buildCell(index), + ), + ); + }, + separatorBuilder: (_, __) { + return const SizedBox( + height: 10, + ); + }, + itemCount: getIt().historyAccounts.length + 1), + ), + ], + ), + ), + ), + ); + } + + Widget buildCell(int index) { + Widget child = ListTile( + title: Text( + getIt().historyAccounts[index].host ?? "", + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 15, + ), + minVerticalPadding: 10, + subtitle: Padding( + padding: const EdgeInsets.only(top: 10.0), + child: Text( + getIt().historyAccounts[index].userName ?? "", + ), + ), + trailing: index == 0 + ? Container( + padding: const EdgeInsets.symmetric( + horizontal: 5, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + border: Border.all(color: ref.watch(themeProvider).primaryColor, width: 1), + ), + child: Text( + "已登录", + style: TextStyle(color: ref.watch(themeProvider).primaryColor, fontSize: 12), + ), + ) + : (isLoginingHost.isNotEmpty + ? SizedBox( + width: 15, + height: 15, + child: CircularProgressIndicator( + strokeWidth: 2, + color: ref.watch(themeProvider).primaryColor, + ), + ) + : const SizedBox.shrink()), + ); + + if (getIt().historyAccounts[index].host == getIt().host) { + return child; + } + + return Slidable( + key: ValueKey(index), + endActionPane: ActionPane( + motion: const ScrollMotion(), + extentRatio: 0.15, + children: [ + SlidableAction( + backgroundColor: Colors.red, + flex: 1, + onPressed: (_) { + getIt().removeHistoryAccount(getIt().historyAccounts[index].host); + setState(() {}); + }, + foregroundColor: Colors.white, + icon: CupertinoIcons.delete, + ), + ], + ), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + loginNewByBean(getIt().historyAccounts[index]); + }, + child: child), + ); + } + + LoginHelper? helper; + + void loginNewByBean(UserInfoBean historyAccount) async { + isLoginingHost = historyAccount.host ?? ""; + setState(() {}); + helper = LoginHelper( + historyAccount.useSecretLogined, + historyAccount.host ?? "", + historyAccount.userName ?? "", + historyAccount.password ?? "", + true, + ); + var response = await helper!.login(); + dealLoginResponse(response); + } + + void dealLoginResponse(int response) { + if (response == LoginHelper.success) { + Navigator.of(context).pushNamedAndRemoveUntil(Routes.routeHomePage, (_) => false); + } else if (response == LoginHelper.failed) { + loginFailed(); + } else { + twoFact(); + } + } + + void loginFailed() { + isLoginingHost = ""; + Http.clear(); + getIt().updateHost(preHost); + setState(() {}); + } + + void twoFact() { + String twoFact = ""; + showCupertinoDialog( + context: context, + builder: (_) => CupertinoAlertDialog( + title: const Text("两步验证"), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Material( + color: Colors.transparent, + child: TextField( + onChanged: (value) { + twoFact = value; + }, + maxLines: 1, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), + hintText: "请输入code", + ), + autofocus: true, + ), + ), + ], + ), + actions: [ + CupertinoDialogAction( + child: const Text( + "取消", + style: TextStyle( + color: Color(0xff999999), + ), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + CupertinoDialogAction( + child: Text( + "确定", + style: TextStyle( + color: ref.watch(themeProvider).primaryColor, + ), + ), + onPressed: () async { + Navigator.of(context).pop(true); + if (helper != null) { + var response = await helper!.loginTwice(twoFact); + dealLoginResponse(response); + } else { + "状态异常".toast(); + } + }, + ), + ], + )).then((value) { + if (value == null) { + isLoginingHost = ""; + setState(() {}); + } + }); + } + + Widget addAccount() { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.of(context).pushNamedAndRemoveUntil( + Routes.routeLogin, + (_) => false, + arguments: true, + ); + }, + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 15, + horizontal: 15, + ), + decoration: BoxDecoration( + color: ref.watch(themeProvider).themeColor.settingBordorColor(), + borderRadius: BorderRadius.circular(15), + ), + child: Row( + children: [ + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + border: Border.all( + color: ref.watch(themeProvider).themeColor.descColor(), + ), + ), + child: Icon( + CupertinoIcons.add, + color: ref.watch(themeProvider).themeColor.descColor(), + ), + ), + const SizedBox( + width: 15, + ), + Text( + "添加账号", + style: TextStyle( + color: ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 16, + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/module/env/env_page.dart b/lib/module/env/env_page.dart index 2dd0137..aee9752 100644 --- a/lib/module/env/env_page.dart +++ b/lib/module/env/env_page.dart @@ -8,6 +8,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/empty_widget.dart'; +import 'package:qinglong_app/base/ui/search_cell.dart'; import 'package:qinglong_app/module/env/env_bean.dart'; import 'package:qinglong_app/module/env/env_viewmodel.dart'; import 'package:qinglong_app/utils/extension.dart'; @@ -22,6 +23,7 @@ class EnvPage extends StatefulWidget { class _EnvPageState extends State { final TextEditingController _searchController = TextEditingController(); + String currentState = EnvViewModel.allStr; @override void initState() { @@ -35,100 +37,158 @@ class _EnvPageState extends State { Widget build(BuildContext context) { return BaseStateWidget( builder: (ref, model, child) { + List prepareList = []; List list = []; + if (currentState == EnvViewModel.allStr) { + prepareList = model.list; + } else if (currentState == EnvViewModel.enabledStr) { + prepareList = model.enabledList; + } else { + prepareList = model.disabledList; + } - for (int i = 0; i < model.list.length; i++) { - EnvBean value = model.list[i]; + for (int i = 0; i < prepareList.length; i++) { + EnvBean value = prepareList[i]; if (_searchController.text.isEmpty || (value.name?.contains(_searchController.text) ?? false) || (value.value?.contains(_searchController.text) ?? false) || (value.remarks?.contains(_searchController.text) ?? false)) { - list.add(EnvItemCell( - value, - i, - ref, - key: ValueKey(value.sId), - )); + list.add( + EnvItemCell( + value, + i, + ref, + key: ValueKey(value.sId), + ), + ); } } return model.list.isEmpty ? const EmptyWidget() : RefreshIndicator( + notificationPredicate: (_) { + return true; + }, color: Theme.of(context).primaryColor, onRefresh: () async { return model.loadData(false); }, child: SlidableAutoCloseBehavior( - child: ReorderableListView( - keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, - header: searchCell(ref), - onReorder: (int oldIndex, int newIndex) { - if (list.length != model.list.length) { - "请先清空搜索关键词".toast(); - return; - } + child: currentState == EnvViewModel.disabledStr + ? ListView( + children: [ + searchCell(context, ref), + ...list, + ], + ) + : ReorderableListView( + keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, + header: searchCell(context, ref), + onReorder: (int oldIndex, int newIndex) { + if (list.length != model.list.length) { + "请先清空搜索关键词".toast(); + return; + } - setState(() { - //交换数据 - if (newIndex > oldIndex) { - newIndex -= 1; - } - final EnvBean item = model.list.removeAt(oldIndex); - model.list.insert(newIndex, item); - model.update(item.sId ?? "", newIndex, oldIndex); - }); - }, - children: list, - ), + setState( + () { + //交换数据 + if (newIndex > oldIndex) { + newIndex -= 1; + } + final EnvBean item = model.list.removeAt(oldIndex); + model.list.insert(newIndex, item); + model.update(item.sId ?? "", newIndex, oldIndex); + }, + ); + }, + children: list, + ), ), ); }, model: envProvider, onReady: (viewModel) { - viewModel.loadData(); + viewModel.loadData(true); }, ); } - Widget searchCell(WidgetRef context) { + Widget searchCell(BuildContext context, WidgetRef ref) { return Container( - padding: const EdgeInsets.symmetric( - horizontal: 15, - vertical: 10, + color: ref.watch(themeProvider).themeColor.settingBgColor(), + padding: const EdgeInsets.only( + left: 15, ), - child: CupertinoSearchTextField( - onSubmitted: (value) { - setState(() {}); - }, - onSuffixTap: () { - _searchController.text = ""; - setState(() {}); - }, - controller: _searchController, - borderRadius: BorderRadius.circular( - 30, - ), - padding: const EdgeInsets.symmetric( - horizontal: 5, - vertical: 5, - ), - suffixInsets: const EdgeInsets.only( - right: 15, - ), - prefixInsets: EdgeInsets.only( - top: Platform.isAndroid ? 10 : 6, - bottom: 6, - left: 15, - ), - placeholderStyle: TextStyle( - fontSize: 16, - color: context.watch(themeProvider).themeColor.descColor(), - ), - style: const TextStyle( - fontSize: 16, - ), - placeholder: "搜索", + child: Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 10, + ), + child: SearchCell( + controller: _searchController, + ), + ), + ), + Material( + color: Colors.transparent, + child: PopupMenuButton( + onSelected: (String result) { + currentState = result; + setState(() {}); + }, + itemBuilder: (BuildContext context) => [ + PopupMenuItem( + child: Text( + EnvViewModel.allStr, + style: TextStyle( + color: currentState == EnvViewModel.allStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 14, + ), + ), + value: EnvViewModel.allStr, + ), + PopupMenuItem( + child: Text( + EnvViewModel.enabledStr, + style: TextStyle( + color: currentState == EnvViewModel.enabledStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 14, + ), + ), + value: EnvViewModel.enabledStr, + ), + PopupMenuItem( + child: Text( + EnvViewModel.disabledStr, + style: TextStyle( + color: + currentState == EnvViewModel.disabledStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 14, + ), + ), + value: EnvViewModel.disabledStr, + ), + ], + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + vertical: 10, + ), + child: Text( + "筛选", + style: TextStyle( + color: ref.watch(themeProvider).themeColor.descColor(), + fontSize: 14, + ), + ), + ), + ), + ), + ], ), ); } @@ -143,91 +203,96 @@ class EnvItemCell extends StatelessWidget { @override Widget build(BuildContext context) { - return ColoredBox( - color: ref.watch(themeProvider).themeColor.settingBgColor(), - child: Slidable( - key: ValueKey(bean.sId), - endActionPane: ActionPane( - motion: const StretchMotion(), - extentRatio: 0.5, + return Slidable( + key: ValueKey(bean.sId), + endActionPane: ActionPane( + motion: const StretchMotion(), + extentRatio: 0.5, + children: [ + SlidableAction( + backgroundColor: const Color(0xff5D5E70), + onPressed: (_) { + Navigator.of(context).pushNamed(Routes.routeAddEnv, arguments: bean); + }, + foregroundColor: Colors.white, + icon: CupertinoIcons.pencil_outline, + ), + SlidableAction( + backgroundColor: const Color(0xffA356D6), + onPressed: (_) { + enableEnv(context); + }, + foregroundColor: Colors.white, + icon: bean.status == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp, + ), + SlidableAction( + backgroundColor: const Color(0xffEA4D3E), + onPressed: (_) { + delEnv(context, ref); + }, + foregroundColor: Colors.white, + icon: CupertinoIcons.delete, + ), + ], + ), + child: SizedBox( + width: MediaQuery.of(context).size.width, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SlidableAction( - backgroundColor: const Color(0xff5D5E70), - onPressed: (_) { - Navigator.of(context).pushNamed(Routes.routeAddEnv, arguments: bean); - }, - foregroundColor: Colors.white, - icon: CupertinoIcons.pencil_outline, - ), - SlidableAction( - backgroundColor: const Color(0xffA356D6), - onPressed: (_) { - enableEnv(context); - }, - foregroundColor: Colors.white, - icon: bean.status == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp, - ), - SlidableAction( - backgroundColor: const Color(0xffEA4D3E), - onPressed: (_) { - delEnv(context, ref); - }, - foregroundColor: Colors.white, - icon: CupertinoIcons.delete, - ), - ], - ), - child: SizedBox( - width: MediaQuery.of(context).size.width, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Material( - color: ref.watch(themeProvider).themeColor.settingBgColor(), - child: InkWell( - onTap: () { - Navigator.of(context).pushNamed(Routes.routeEnvDetail, arguments: bean); - }, - child: Container( - 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( - children: [ - bean.status == 1 - ? const Icon( - Icons.dnd_forwardslash, - size: 18, - color: Color(0xffEA4D3E), - ) - : Container( - padding: const EdgeInsets.symmetric( - horizontal: 5, - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - border: Border.all(color: ref.watch(themeProvider).primaryColor, width: 1), - ), - child: Text( - "${getIndexByIndex(context, index)}", - style: TextStyle(color: ref.watch(themeProvider).primaryColor, fontSize: 12), + Material( + color: ref.watch(themeProvider).themeColor.settingBgColor(), + child: InkWell( + onTap: () { + Navigator.of(context).pushNamed(Routes.routeEnvDetail, arguments: bean); + }, + child: Container( + 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( + children: [ + bean.status == 1 + ? const SizedBox( + width: 18, + ) + : Container( + padding: const EdgeInsets.symmetric( + horizontal: 5, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(3), + border: Border.all(color: ref.watch(themeProvider).themeColor.descColor(), width: 1), + ), + child: Text( + "${getIndexByIndex(context, index)}", + style: TextStyle( + color: ref.watch(themeProvider).themeColor.descColor(), + fontSize: 12, ), ), - const SizedBox( - width: 5, + ), + const SizedBox( + width: 5, + ), + ConstrainedBox( + constraints: BoxConstraints.loose( + Size.fromWidth( + MediaQuery.of(context).size.width / 2, + ), ), - Material( + child: Material( color: Colors.transparent, child: Text( bean.name ?? "", @@ -239,73 +304,92 @@ class EnvItemCell extends StatelessWidget { ), ), ), - const SizedBox( - width: 5, + ), + const SizedBox( + width: 5, + ), + ConstrainedBox( + constraints: BoxConstraints.loose( + Size.fromWidth( + MediaQuery.of(context).size.width / 3, + ), ), - Expanded( - child: Visibility( - visible: bean.remarks != null && bean.remarks!.isNotEmpty, - child: Material( - color: Colors.transparent, - child: Text( - "(${bean.remarks})", - maxLines: 1, - style: TextStyle( - height: 1, - overflow: TextOverflow.ellipsis, - color: ref.watch(themeProvider).themeColor.descColor(), - fontSize: 12, - ), + child: Visibility( + visible: bean.remarks != null && bean.remarks!.isNotEmpty, + child: Material( + color: Colors.transparent, + child: Text( + "(${bean.remarks})", + maxLines: 1, + style: TextStyle( + height: 1, + overflow: TextOverflow.ellipsis, + color: ref.watch(themeProvider).themeColor.descColor(), + fontSize: 12, ), ), ), ), - ], - ), - ), - const SizedBox( - width: 15, - ), - Material( - color: Colors.transparent, - child: Text( - Utils.formatGMTTime(bean.timestamp ?? ""), - maxLines: 1, - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: ref.watch(themeProvider).themeColor.descColor(), - fontSize: 12, ), - ), - ), - ], - ), - const SizedBox( - height: 15, - ), - Material( - color: Colors.transparent, - child: Text( - bean.value ?? "", - maxLines: 1, - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: ref.watch(themeProvider).themeColor.descColor(), - fontSize: 12, + const SizedBox( + width: 7, + ), + bean.status == 1 + ? Image.asset( + "assets/images/icon_disabled.png", + fit: BoxFit.cover, + width: 35, + ) + : Image.asset( + "assets/images/icon_enable.png", + fit: BoxFit.cover, + width: 35, + ) + ], ), ), + const SizedBox( + width: 15, + ), + Material( + color: Colors.transparent, + child: Text( + Utils.formatGMTTime(bean.timestamp ?? ""), + maxLines: 1, + style: TextStyle( + overflow: TextOverflow.ellipsis, + color: ref.watch(themeProvider).themeColor.descColor(), + fontSize: 12, + ), + ), + ), + ], + ), + const SizedBox( + height: 15, + ), + Material( + color: Colors.transparent, + child: Text( + bean.value ?? "", + maxLines: 1, + style: TextStyle( + overflow: TextOverflow.ellipsis, + color: ref.watch(themeProvider).themeColor.descColor(), + fontSize: 12, + ), ), - ], - ), + ), + ], ), ), ), - const Divider( - height: 1, - indent: 15, - ), - ], - ), + ), + const Divider( + height: 1, + indent: 15, + ), + ], ), ), ); diff --git a/lib/module/env/env_viewmodel.dart b/lib/module/env/env_viewmodel.dart index 2bd4c90..7c6f440 100644 --- a/lib/module/env/env_viewmodel.dart +++ b/lib/module/env/env_viewmodel.dart @@ -8,7 +8,13 @@ import 'package:qinglong_app/utils/extension.dart'; var envProvider = ChangeNotifierProvider((ref) => EnvViewModel()); class EnvViewModel extends BaseViewModel { + static const String allStr = "全部"; + static const String disabledStr = "已禁用"; + static const String enabledStr = "已启用"; List list = []; + List disabledList = []; + List enabledList = []; + Future loadData([isLoading = true]) async { if (isLoading) { @@ -17,12 +23,19 @@ class EnvViewModel extends BaseViewModel { HttpResponse> result = await Api.envs(""); + if (result.success && result.bean != null) { list.clear(); list.addAll(result.bean!); + disabledList.clear(); + disabledList.addAll(list.where((element) => element.status == 1).toList()); + enabledList.clear(); + enabledList.addAll(list.where((element) => element.status == 0).toList()); success(); } else { list.clear(); + disabledList.clear(); + enabledList.clear(); failed(result.message, notify: true); } } @@ -31,23 +44,14 @@ class EnvViewModel extends BaseViewModel { HttpResponse result = await Api.delEnv(id); if (result.success) { "删除成功".toast(); - list.removeWhere((element) => element.sId == id); - notifyListeners(); + loadData(false); } else { failed(result.message, notify: true); } } void updateEnv(EnvBean result) { - if (result.sId == null) { - loadData(false); - return; - } - EnvBean bean = list.firstWhere((element) => element.sId == result.sId); - bean.name = result.name; - bean.remarks = result.remarks; - bean.value = result.value; - notifyListeners(); + loadData(false); } Future enableEnv(String sId, int status) async { @@ -56,8 +60,7 @@ class EnvViewModel extends BaseViewModel { if (response.success) { "启用成功".toast(); - list.firstWhere((element) => element.sId == sId).status = 0; - success(); + loadData(false); } else { failToast(response.message, notify: true); } @@ -66,8 +69,7 @@ class EnvViewModel extends BaseViewModel { if (response.success) { "禁用成功".toast(); - list.firstWhere((element) => element.sId == sId).status = 1; - success(); + loadData(false); } else { failToast(response.message, notify: true); } diff --git a/lib/module/others/login_log/login_log_page.dart b/lib/module/others/login_log/login_log_page.dart index 70191f9..bc4afc9 100644 --- a/lib/module/others/login_log/login_log_page.dart +++ b/lib/module/others/login_log/login_log_page.dart @@ -37,76 +37,99 @@ class _LoginLogPageState extends ConsumerState ), body: list.isEmpty ? const Center( - child: CupertinoActivityIndicator(), - ) - : ListView.builder( - itemBuilder: (context, index) { - LoginLogBean item = list[index]; + child: CupertinoActivityIndicator(), + ) + : ListView.separated( + itemBuilder: (context, index) { + LoginLogBean item = list[index]; - return ColoredBox( - color: ref.watch(themeProvider).themeColor.settingBgColor(), - child: ListTile( - isThreeLine: true, - title: Text( - Utils.formatMessageTime(item.timestamp ?? 0), - style: TextStyle( - fontSize: 16, - color: ref.watch(themeProvider).themeColor.titleColor(), - ), - ), - subtitle: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox( - height: 5, - ), - SelectableText( - "${item.address}", - selectionWidthStyle: BoxWidthStyle.max, - selectionHeightStyle: BoxHeightStyle.max, - style: TextStyle( - color: - ref.watch(themeProvider).themeColor.descColor(), - fontSize: 14, - ), - ), - const SizedBox( - height: 5, - ), - SelectableText( - "${item.ip}", - selectionWidthStyle: BoxWidthStyle.max, - selectionHeightStyle: BoxHeightStyle.max, - style: TextStyle( - color: - ref.watch(themeProvider).themeColor.descColor(), - fontSize: 14, - ), - ), - ], - ), - trailing: item.status == 0 - ? Icon( - CupertinoIcons.checkmark_circle, - color: ref.watch(themeProvider).primaryColor, - size: 16, - ) - : const Icon( - CupertinoIcons.clear_circled, - color: Colors.red, - size: 16, - ), + return Row( + children: [ + const SizedBox( + width: 15, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 10, ), - ); - }, - itemCount: list.length, - ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "${item.address}", + style: TextStyle( + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), + fontSize: 14, + ), + ), + const SizedBox( + width: 5, + ), + Padding( + padding: const EdgeInsets.only( + top: 2, + ), + child: Image.asset( + item.status == 0 + ? "assets/images/icon_success.png" + : "assets/images/icon_fail.png", + width: 30, + fit: BoxFit.cover, + ), + ), + ], + ), + const SizedBox( + height: 10, + ), + SelectableText( + "${item.ip}", + selectionWidthStyle: BoxWidthStyle.max, + selectionHeightStyle: BoxHeightStyle.max, + style: TextStyle( + color: + ref.watch(themeProvider).themeColor.descColor(), + fontSize: 14, + ), + ), + const SizedBox( + height: 10, + ), + ], + ), + const Spacer(), + Text( + Utils.formatMessageTime(item.timestamp ?? 0), + style: TextStyle( + fontSize: 12, + color: ref.watch(themeProvider).themeColor.descColor(), + ), + ), + const SizedBox( + width: 15, + ), + ], + ); + }, + itemCount: list.length, + separatorBuilder: (BuildContext context, int index) { + return const Divider( + indent: 15, + height: 1, + ); + }, + ), ); } Future loadData() async { - HttpResponse> response = await Api.loginLog(); + HttpResponse> response = + await Api.loginLog(); if (response.success) { if (response.bean == null || response.bean!.isEmpty) { diff --git a/lib/module/others/other_page.dart b/lib/module/others/other_page.dart index e65d464..5c64899 100644 --- a/lib/module/others/other_page.dart +++ b/lib/module/others/other_page.dart @@ -26,15 +26,8 @@ class _OtherPageState extends ConsumerState { children: [ Container( margin: const EdgeInsets.symmetric( - horizontal: 15, vertical: 15, ), - decoration: BoxDecoration( - color: ref.watch(themeProvider).themeColor.settingBordorColor(), - borderRadius: const BorderRadius.all( - Radius.circular(15), - ), - ), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -225,15 +218,8 @@ class _OtherPageState extends ConsumerState { ), Container( margin: const EdgeInsets.symmetric( - horizontal: 15, vertical: 15, ), - decoration: BoxDecoration( - color: ref.watch(themeProvider).themeColor.settingBordorColor(), - borderRadius: const BorderRadius.all( - Radius.circular(15), - ), - ), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -304,6 +290,41 @@ class _OtherPageState extends ConsumerState { const Divider( indent: 15, ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.of(context).pushNamed(Routes.routeChangeAccount); + }, + child: Padding( + padding: const EdgeInsets.only( + left: 15, + right: 15, + top: 5, + bottom: 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: () { diff --git a/lib/module/others/scripts/script_page.dart b/lib/module/others/scripts/script_page.dart index 34c3425..de28a58 100644 --- a/lib/module/others/scripts/script_page.dart +++ b/lib/module/others/scripts/script_page.dart @@ -7,6 +7,7 @@ import 'package:qinglong_app/base/ql_app_bar.dart'; import 'package:qinglong_app/base/routes.dart'; import 'package:qinglong_app/base/theme.dart'; import 'package:qinglong_app/base/ui/lazy_load_state.dart'; +import 'package:qinglong_app/base/ui/search_cell.dart'; import 'package:qinglong_app/module/others/scripts/script_bean.dart'; import 'package:qinglong_app/utils/extension.dart'; @@ -170,39 +171,7 @@ class _ScriptPageState extends ConsumerState with LazyLoadState with LazyLoadState { List list = []; + final TextEditingController _searchController = TextEditingController(); + + Widget searchCell(WidgetRef context) { + return Container( + padding: const EdgeInsets.symmetric( + horizontal: 15, + vertical: 10, + ), + child: SearchCell( + controller: _searchController, + ), + ); + } + + @override + void initState() { + super.initState(); + _searchController.addListener(() { + setState(() {}); + }); + } @override Widget build(BuildContext context) { @@ -37,72 +59,79 @@ class _TaskLogPageState extends ConsumerState with LazyLoadState ListTile( - onTap: () { - Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: { - "path": item.name, - "title": e, - }); - }, - title: Text( - e, - style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), - fontSize: 14, - ), - ), - )) - .toList() - : (item.children ?? []) - .map((e) => ListTile( - onTap: () { - Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: { - "path": item.name, - "title": e.title, - }); - }, - title: Text( - e.title ?? "", - style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), - fontSize: 14, - ), - ), - )) - .toList(), - ) + title: Text( + item.name ?? "", + style: TextStyle( + color: ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 16, + ), + ), + children: (item.files?.isNotEmpty ?? false) + ? item.files! + .map((e) => ListTile( + onTap: () { + Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: { + "path": item.name, + "title": e, + }); + }, + title: Text( + e, + style: TextStyle( + color: ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 14, + ), + ), + )) + .toList() + : (item.children ?? []) + .map((e) => ListTile( + onTap: () { + Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: { + "path": item.name, + "title": e.title, + }); + }, + title: Text( + e.title ?? "", + style: TextStyle( + color: ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 14, + ), + ), + )) + .toList(), + ) : ListTile( - onTap: () { - if (item.isDir ?? false) { - "该文件夹为空".toast(); - return; - } - - Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: item.name); - }, - title: Text( - item.name ?? "", - style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), - fontSize: 16, - ), - ), - ), + onTap: () { + if (item.isDir ?? false) { + "该文件夹为空".toast(); + return; + } + Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: { + "path": "", + "title": item.name, + }); + }, + title: Text( + item.name ?? "", + style: TextStyle( + color: ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 16, + ), + ), + ), ); }, itemCount: list.length, diff --git a/lib/module/task/intime_log/intime_log_page.dart b/lib/module/task/intime_log/intime_log_page.dart index 1c0253a..bf86d48 100644 --- a/lib/module/task/intime_log/intime_log_page.dart +++ b/lib/module/task/intime_log/intime_log_page.dart @@ -10,8 +10,7 @@ class InTimeLogPage extends StatefulWidget { final String cronId; final bool needTimer; - const InTimeLogPage(this.cronId, this.needTimer, {Key? key}) - : super(key: key); + const InTimeLogPage(this.cronId, this.needTimer, {Key? key}) : super(key: key); @override _InTimeLogPageState createState() => _InTimeLogPageState(); @@ -25,28 +24,28 @@ class _InTimeLogPageState extends State { @override void initState() { super.initState(); - - if (widget.needTimer) { - _timer = Timer.periodic( - const Duration(seconds: 2), - (timer) { - getLogData(); - }, - ); - } else { - WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { + _timer = Timer.periodic( + const Duration(seconds: 2), + (timer) { getLogData(); - }); - } + }, + ); } + bool isRequest = false; + bool canRequest = true; + getLogData() async { + if (!canRequest) return; + if (isRequest) return; + isRequest = true; HttpResponse response = await Api.inTimeLog(widget.cronId); if (response.success) { content = response.bean; setState(() {}); } + isRequest = false; } @override diff --git a/lib/module/task/task_page.dart b/lib/module/task/task_page.dart index 7726cae..b1cd573 100644 --- a/lib/module/task/task_page.dart +++ b/lib/module/task/task_page.dart @@ -7,6 +7,7 @@ import 'package:flutter_slidable/flutter_slidable.dart'; 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/search_cell.dart'; import 'package:qinglong_app/module/task/intime_log/intime_log_page.dart'; import 'package:qinglong_app/module/task/task_bean.dart'; import 'package:qinglong_app/module/task/task_viewmodel.dart'; @@ -50,7 +51,7 @@ class _TaskPageState extends ConsumerState { return RefreshIndicator( color: Theme.of(context).primaryColor, onRefresh: () async { - return model.loadData( false); + return model.loadData(false); }, child: IconTheme( data: const IconThemeData( @@ -100,45 +101,20 @@ class _TaskPageState extends ConsumerState { Widget searchCell(WidgetRef context) { return Container( - padding: const EdgeInsets.symmetric( - horizontal: 15, - vertical: 10, + color: ref.watch(themeProvider).themeColor.settingBgColor(), + padding: const EdgeInsets.only( + left: 15, ), child: Row( children: [ Expanded( - child: CupertinoSearchTextField( - onSubmitted: (value) { - setState(() {}); - }, - onSuffixTap: () { - _searchController.text = ""; - setState(() {}); - }, - controller: _searchController, - borderRadius: BorderRadius.circular( - 30, - ), + child: Padding( padding: const EdgeInsets.symmetric( - horizontal: 5, - vertical: 5, + vertical: 10, ), - suffixInsets: const EdgeInsets.only( - right: 15, + child: SearchCell( + controller: _searchController, ), - prefixInsets: EdgeInsets.only( - top: Platform.isAndroid ? 10 : 6, - bottom: 6, - left: 15, - ), - placeholderStyle: TextStyle( - fontSize: 16, - color: context.watch(themeProvider).themeColor.descColor(), - ), - style: const TextStyle( - fontSize: 16, - ), - placeholder: "搜索", ), ), Material( @@ -164,7 +140,7 @@ class _TaskPageState extends ConsumerState { TaskViewModel.runningStr, style: TextStyle( color: - currentState == TaskViewModel.runningStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + currentState == TaskViewModel.runningStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), fontSize: 14, ), ), @@ -202,15 +178,16 @@ class _TaskPageState extends ConsumerState { style: TextStyle( fontSize: 14, color: - currentState == TaskViewModel.disableStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + currentState == TaskViewModel.disableStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), ), ), value: TaskViewModel.disableStr, ), ], child: Padding( - padding: const EdgeInsets.only( - left: 10, + padding: const EdgeInsets.symmetric( + horizontal: 15, + vertical: 10, ), child: Text( "筛选", @@ -258,7 +235,7 @@ class TaskItemCell extends StatelessWidget { @override Widget build(BuildContext context) { return ColoredBox( - color: ref.watch(themeProvider).themeColor.settingBgColor(), + color: bean.isPinned == 1 ? ref.watch(themeProvider).themeColor.pinColor() : ref.watch(themeProvider).themeColor.settingBgColor(), child: Slidable( key: ValueKey(bean.sId), endActionPane: ActionPane( @@ -268,7 +245,7 @@ class TaskItemCell extends StatelessWidget { SlidableAction( backgroundColor: const Color(0xff5D5E70), onPressed: (_) { - WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance?.endOfFrame.then((timeStamp) { Navigator.of(context).pushNamed(Routes.routeAddTask, arguments: bean); }); }, @@ -278,19 +255,15 @@ class TaskItemCell extends StatelessWidget { SlidableAction( backgroundColor: const Color(0xffF19A39), onPressed: (_) { - WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { - pinTask(context); - }); + pinTask(context); }, foregroundColor: Colors.white, - icon: bean.isPinned! == 0 ? CupertinoIcons.pin : CupertinoIcons.pin_slash, + icon: (bean.isPinned ?? 0) == 0 ? CupertinoIcons.pin : CupertinoIcons.pin_slash, ), SlidableAction( backgroundColor: const Color(0xffA356D6), onPressed: (_) { - WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { - enableTask(context); - }); + enableTask(context); }, foregroundColor: Colors.white, icon: bean.isDisabled! == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp, @@ -298,9 +271,7 @@ class TaskItemCell extends StatelessWidget { SlidableAction( backgroundColor: const Color(0xffEA4D3E), onPressed: (_) { - WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { - delTask(context, ref); - }); + delTask(context, ref); }, foregroundColor: Colors.white, icon: CupertinoIcons.delete, @@ -314,13 +285,17 @@ class TaskItemCell extends StatelessWidget { SlidableAction( backgroundColor: const Color(0xffD25535), onPressed: (_) { - WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { - if (bean.status! == 1) { - startCron(context, ref); - } else { - stopCron(context, ref); - } - }); + if (bean.status! == 1) { + startCron( + context, + ref, + ); + } else { + stopCron( + context, + ref, + ); + } }, foregroundColor: Colors.white, icon: bean.status! == 1 ? CupertinoIcons.memories : CupertinoIcons.stop_circle, @@ -328,7 +303,10 @@ class TaskItemCell extends StatelessWidget { SlidableAction( backgroundColor: const Color(0xff606467), onPressed: (_) { - WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { + Future.delayed( + const Duration( + milliseconds: 250, + ), () { logCron(context, ref); }); }, @@ -338,14 +316,14 @@ class TaskItemCell extends StatelessWidget { ], ), child: Material( - color: ref.watch(themeProvider).themeColor.settingBgColor(), + color: bean.isPinned == 1 ? ref.watch(themeProvider).themeColor.pinColor() : ref.watch(themeProvider).themeColor.settingBgColor(), child: InkWell( onTap: () { Navigator.of(context).pushNamed(Routes.routeTaskDetail, arguments: bean); }, child: Container( width: MediaQuery.of(context).size.width, - color: bean.isPinned == 1 ? ref.watch(themeProvider).themeColor.pinColor() : Colors.transparent, + color: Colors.transparent, padding: const EdgeInsets.symmetric( horizontal: 15, vertical: 8, @@ -363,30 +341,12 @@ class TaskItemCell extends StatelessWidget { mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, children: [ - bean.isDisabled == 1 - ? const Icon( - Icons.dnd_forwardslash, - size: 18, - color: Color(0xffEA4D3E), - ) - : const SizedBox.shrink(), - SizedBox( - width: bean.isDisabled == 1 ? 5 : 0, - ), - bean.status == 1 - ? const SizedBox.shrink() - : SizedBox( - width: 13, - height: 13, - child: CircularProgressIndicator( - strokeWidth: 2, - color: ref.watch(themeProvider).primaryColor, - ), - ), - SizedBox( - width: bean.status == 1 ? 0 : 5, - ), - Expanded( + ConstrainedBox( + constraints: BoxConstraints.loose( + Size.fromWidth( + MediaQuery.of(context).size.width / 2, + ), + ), child: Material( color: Colors.transparent, child: Text( @@ -401,6 +361,30 @@ class TaskItemCell extends StatelessWidget { ), ), ), + const SizedBox( + width: 7, + ), + bean.status == 0 + ? Image.asset( + "assets/images/icon_running.png", + fit: BoxFit.cover, + width: 45, + ) + : Image.asset( + "assets/images/icon_idle.png", + fit: BoxFit.cover, + width: 45, + ), + const SizedBox( + width: 7, + ), + bean.isDisabled == 1 + ? Image.asset( + "assets/images/icon_task_disable.png", + fit: BoxFit.cover, + width: 45, + ) + : const SizedBox.shrink() ], ), ), @@ -459,52 +443,50 @@ class TaskItemCell extends StatelessWidget { } startCron(BuildContext context, WidgetRef ref) async { - await ref.read(taskProvider).runCrons( bean.sId!); - WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { + await ref.read(taskProvider).runCrons(bean.sId!); + Future.delayed(const Duration(milliseconds: 250), () { logCron(context, ref); }); } stopCron(BuildContext context, WidgetRef ref) { - ref.read(taskProvider).stopCrons( bean.sId!); + ref.read(taskProvider).stopCrons(bean.sId!); } logCron(BuildContext context, WidgetRef ref) { - WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { - showCupertinoDialog( - useRootNavigator: false, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - "${bean.name}运行日志", - maxLines: 1, - style: const TextStyle(overflow: TextOverflow.ellipsis), - ), - content: InTimeLogPage(bean.sId!, bean.status == 0), - actions: [ - CupertinoDialogAction( - child: Text( - "知道了", - style: TextStyle(color: Theme.of(context).primaryColor), - ), - onPressed: () { - Navigator.of(context).pop(); - ref.read(taskProvider).loadData( false); - }, + showCupertinoDialog( + useRootNavigator: false, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text( + "${bean.name}运行日志", + maxLines: 1, + style: const TextStyle(overflow: TextOverflow.ellipsis), + ), + content: InTimeLogPage(bean.sId!, bean.status == 0), + actions: [ + CupertinoDialogAction( + child: Text( + "知道了", + style: TextStyle(color: Theme.of(context).primaryColor), ), - ], - ); - }, - context: context); - }); + onPressed: () { + Navigator.of(context).pop(); + ref.read(taskProvider).loadData(false); + }, + ), + ], + ); + }, + context: context); } void enableTask(BuildContext context) { - ref.read(taskProvider).enableTask( bean.sId!, bean.isDisabled!); + ref.read(taskProvider).enableTask(bean.sId!, bean.isDisabled!); } void pinTask(BuildContext context) { - ref.read(taskProvider).pinTask( bean.sId!, bean.isPinned!); + ref.read(taskProvider).pinTask(bean.sId!, bean.isPinned!); } void delTask(BuildContext context, WidgetRef ref) {