From 1298dba5909d8cb8d2c6197dfb277fdf045807a9 Mon Sep 17 00:00:00 2001 From: jyuesong <425698907@qq.com> Date: Thu, 16 Jun 2022 14:37:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=8A=E4=BC=A0=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/images/add_btn_svip.png | Bin 0 -> 4736 bytes assets/images/icon_add_file.png | Bin 0 -> 10932 bytes assets/images/js.png | Bin 0 -> 2116 bytes assets/images/json.png | Bin 0 -> 3041 bytes assets/images/other.png | Bin 0 -> 2181 bytes assets/images/py.png | Bin 0 -> 4381 bytes assets/images/shell.png | Bin 0 -> 1718 bytes assets/images/ts.png | Bin 0 -> 1412 bytes lib/base/base_state_widget.dart | 4 +- lib/base/http/api.dart | 48 +- lib/base/http/http.dart | 16 +- lib/base/http/token_interceptor.dart | 3 +- lib/base/http/url.dart | 117 +++-- lib/base/routes.dart | 3 +- lib/base/ui/ql_context_menu.dart | 126 ++++-- lib/base/ui/search_cell.dart | 5 +- lib/base/ui/source_code_view.dart | 5 +- lib/base/ui/syntax_highlighter.dart | 5 +- lib/base/userinfo_viewmodel.dart | 17 +- lib/json.jc.dart | 135 +++--- lib/main.dart | 10 +- lib/module/change_account_page.dart | 162 +++---- lib/module/config/config_edit_page.dart | 21 +- lib/module/config/config_page.dart | 19 +- lib/module/env/add_env_page.dart | 8 +- lib/module/env/env_bean.dart | 13 +- lib/module/env/env_detail_page.dart | 13 +- lib/module/env/env_page.dart | 71 ++- lib/module/env/env_viewmodel.dart | 5 +- lib/module/login/login_page.dart | 68 ++- lib/module/login/user_bean.dart | 1 + lib/module/others/about_page.dart | 4 +- .../others/dependencies/dependency_page.dart | 25 +- .../dependencies/dependency_viewmodel.dart | 5 +- .../others/login_log/login_log_page.dart | 171 ++++--- lib/module/others/other_page.dart | 50 ++- .../scripts/script_code_detail_page.dart | 154 +++++++ .../others/scripts/script_detail_page.dart | 65 +-- .../others/scripts/script_edit_page.dart | 9 +- lib/module/others/scripts/script_page.dart | 322 +++++-------- .../others/scripts/script_upload_page.dart | 425 ++++++++++++++++++ .../others/task_log/task_log_detail_page.dart | 21 +- lib/module/others/task_log/task_log_page.dart | 56 ++- lib/module/others/theme_page.dart | 16 +- lib/module/task/add_task_page.dart | 7 +- .../task/intime_log/intime_log_page.dart | 5 +- lib/module/task/task_bean.dart | 32 +- .../task/task_detail/task_detail_page.dart | 33 +- lib/module/task/task_page.dart | 91 +++- lib/module/task/task_viewmodel.dart | 22 +- lib/utils/utils.dart | 1 + .../example/lib/readme/fib.dart | 6 +- .../lib/src/code_controller.dart | 25 +- pub/code_field-master/lib/src/code_field.dart | 22 +- .../lib/src/code_modifier.dart | 15 +- pubspec.lock | 14 + pubspec.yaml | 1 + test/widget_test.dart | 4 +- 58 files changed, 1702 insertions(+), 774 deletions(-) create mode 100644 assets/images/add_btn_svip.png create mode 100644 assets/images/icon_add_file.png create mode 100644 assets/images/js.png create mode 100644 assets/images/json.png create mode 100644 assets/images/other.png create mode 100644 assets/images/py.png create mode 100644 assets/images/shell.png create mode 100644 assets/images/ts.png create mode 100644 lib/module/others/scripts/script_code_detail_page.dart create mode 100644 lib/module/others/scripts/script_upload_page.dart diff --git a/assets/images/add_btn_svip.png b/assets/images/add_btn_svip.png new file mode 100644 index 0000000000000000000000000000000000000000..fef251ce8f78428404a57efc774b5956e55170cc GIT binary patch literal 4736 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 Hy59dEdEB6A literal 0 HcmV?d00001 diff --git a/assets/images/json.png b/assets/images/json.png new file mode 100644 index 0000000000000000000000000000000000000000..f39a8c44bd1dba6e943023d51d7de8beebcb6ab6 GIT binary patch literal 3041 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 literal 0 HcmV?d00001 diff --git a/assets/images/py.png b/assets/images/py.png new file mode 100644 index 0000000000000000000000000000000000000000..2213506780885fb9e2ab87c96173b56e8473b710 GIT binary patch literal 4381 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 R^LE|=(ALm{maAEZ{2v0-Q-uHk literal 0 HcmV?d00001 diff --git a/assets/images/shell.png b/assets/images/shell.png new file mode 100644 index 0000000000000000000000000000000000000000..9563d70866127919a025589bc2a770aee3ccd651 GIT binary patch literal 1718 zcmb_ddpy%?82@e4Y)mc{bBUtMs*{i;b0%_0vF1{m!!h^!bz3tHMTp3XoG4x7*2N?$ zmqdh$jmQW~C3l-k*yMJ8`|q5;&v`$e=XpNg%kw;cz3-b$z+1^ksYn3;AY*;p+#akK z#DRc=xe@2y3Kj{nnYAMVJPd@_We_97juXisohuFqLqG67NGek-&QcsgeJC{d2ycK! zqiOqx1d=`7!@RXaBYbZOj8y;te$d+7)G_ilpBEV9Kvip=9j$OZFlhj<$xNGU_Lf#k zf+7_{P7pRl?=&|vS5PoxqUBHuo)R9BMab>VN-DE)Dd>c4QsxK+{djZ|v%Wbv<=sGm z=aZnxz7YO|bOnI}#}*a!4F06|taI?|@277$L{-b|RNL6-cV}_27RXYG@zA@y=d}_bd2jODE;(7_kAiGckYu0YO1T>Mb zT(OFQ;D_myKb!t%nVV&viQpAMW>t3o`n5gBXMMlgQgoN+fcdD z$0YfM+g0Uf?s{2;z~&5O)s1xX5}t9mMC^2*GJSw}Ua<>j1Yk~h?XO{I!j9YJ{0R+W z*<-TCe2lbL)E5kUyOC~Q#u)y4`L40{k^)q@Zc_+uAkCu;7I|ucDEx*~%zhO97wWF&~ z@2f5cnV}QYbGE{Fi zP-4-W=g#GQYnAN~v5U|KzS~n2agw8=6W!rHzS_;fy@@|3|ANJf){~77br;8u?(hEf z;4VXBfe0vTjikpfM?ou>y4+nDDSII z>I~P-KANpt-S)0XGu|%>iC&(Y#JJ4Z{0KKhzs**gf7o##wWwRaOlA7=T}_nwfm zg@{yGkGYnmj17yOb~L=tbNAlc2^e||{gduD5)+b-v0aCcRWl&D&qtY9y0aG>=YcAm z5}|7O!8)I}>R_Lp9_)EKdhAklZP|1ds%Xize!&&{aa8z_Tb`&mk7cxHcljN8b!t$6 z5$F#h=GMtuM|U2~$le6@ zY4FzR#%)!X7_dcD-clD4-_$-yXd-0RDCH5-HQw}3(BvNtLDymigY)AkzxX8H%eaf! zP$Ae6S;`&9S+(1~yx(%oV5M8JD%BeXi<_=t)##+o;@0q+x zkl^GV4u!yu$2ltF>SJL$T=vRnkO1V3fJRC5(T4o*GY~ja?x7Lm0_3ghURh8IzcC?} z2J#z0Nls~850uc_xrwqmz_EgUkR#ossNw1X)HRma*VaiF0kF%~)#Bc2?*`Ct?_?ng z1UcTFVqje;UKpR147%&@c};-a3?bVXoN7!c6gR=H>wsYX8bU))shkmKiDTZ(#5IbN~PV literal 0 HcmV?d00001 diff --git a/assets/images/ts.png b/assets/images/ts.png new file mode 100644 index 0000000000000000000000000000000000000000..0bc303668c4d3b67fd1b106e46a14d8f687ca240 GIT binary patch literal 1412 zcmY+@X;4#F6ae6tg?(ZvRrZ1uwStPsI11I$hb1E@vWZf(Eud@)3MDAWG6sQYM{j{~UM<=~_@KPtnEdU2sZ~hyI6y}|NxM&iG{Uz>f zbXZ(`aBL_LA0Kab<$5IUa&SzjU36@CvGlkp03i6@9)8%Ztu5ZPkQ!DFb@#P(^z?_8 z&CBGZj-J-e-nRB`xB}1HI(ypMd&jCMBSqv1{xnx0XjGNt1oDgFKJN(+BL$!^;ZMY6$3F9^gmwHV_(y8m4k6rgEy;(;;V-e zYK9YQhm&fDlVNp?lsd-kw@iFJGxZ%S?L8~~!>`aWhlg!klSk z&5*v#l1FAgvFF;^^IfC!J!A7d;HOB~qD(&&t0d{)7oTjtF#PfC`jBrAOBia@Fq%9LWcY6iBbnq5@Q!IoC% zVTx5LYAc}=#mCSO@!RIV?nHkMa6R#rEZYiiZHdUajBwz0VmQ*UmlH`SY4n=tr# zw|v*3{qUPGj`Q_A3k1j9&B(~ey#F98J14i8071~F&K{~N&rr7p0FVprt}cEF90_~o zSb>juw|pffP}CD~q8w{;%H{wk;$%{0ROMdI%X9-tp*Epi=_S$VE_CQ`EWy#Hn`!D< zCuK2L)b+k3ob%&?1CA3iWfdgZKMHU|&?U${)-pq0aip1k3ls_VBL@(qTSUYm-NV48 zZ^S_7E;>?1ZNOx>l*K*HTIlWsy~d6N8w}=DjfJ^1k(Q_{Ha4O=IDD^sIOIGbuqqAt z6&#d3*_Rf4Bc2$KS6QE9mL;Q{v+VZa?p4f7wMv!PYjbp;Byivy9erFy-u3~3&h5^0 zfZV_)EX@fFtouIG*H^DZ0EG09$-16}~b7#*eINZ5{nE~ep;`0WHoEk)f?t-UDc zD(oJ}0*5y(4LGpj67<{&w4#gri}lj1@^!!?Q0-e=wf9pOu+%c5p#HMJS!T{_#X__| z2)qTEg0)DQltsyMJOP>4@2Cxt50q&J&Cp1fcv7>|6eGw^54F5ky8t2nms}BO0?)=ge#h1ql*20gEEE3dc%+b2_!u1$w;m*(hVm z5iD{7b-c?AixD|RC_g}QwH_5jc7oi4>;r5(Q7CsIU;=2I^3nQWa$JX>i06sVyI4TK zr2&=b2;)utJju7fy)#IIpOCHGecu@bGPGhYdLTo#=qsSihq?4SK-yKPvC)z(U&4zK zhi$|C6LN0YE(N}Num`k?N%p|M9J4gx`kNnY1~QLcuv^=Gf+*ldMb(j$?VW0#t(iUA w#sgM>YJb<~g!k5Ax?4mXpcV6fGHsbrA6A|FjBa)V{vLok*3-52M9`go083s9qW}N^ literal 0 HcmV?d00001 diff --git a/lib/base/base_state_widget.dart b/lib/base/base_state_widget.dart index fb9e9df..d005ff6 100644 --- a/lib/base/base_state_widget.dart +++ b/lib/base/base_state_widget.dart @@ -24,7 +24,9 @@ class BaseStateWidget extends ConsumerStatefulWidget { _BaseStateWidgetState createState() => _BaseStateWidgetState(); } -class _BaseStateWidgetState extends ConsumerState> with LazyLoadState> { +class _BaseStateWidgetState + extends ConsumerState> + with LazyLoadState> { @override Widget build(BuildContext context) { var viewModel = ref.watch(widget.model); diff --git a/lib/base/http/api.dart b/lib/base/http/api.dart index 802ff6c..805bba1 100644 --- a/lib/base/http/api.dart +++ b/lib/base/http/api.dart @@ -89,21 +89,24 @@ class Api { ); } - static Future> startTasks(List crons) async { + static Future> startTasks( + List crons) async { return await Http.put( Url.runTasks, crons, ); } - static Future> stopTasks(List crons) async { + static Future> stopTasks( + List crons) async { return await Http.put( Url.stopTasks, crons, ); } - static Future> updatePassword(String name, String password) async { + static Future> updatePassword( + String name, String password) async { return await Http.put( Url.updatePassword, { @@ -127,7 +130,11 @@ class Api { int? id, String? nId, }) async { - var data = {"name": name, "command": command, "schedule": cron}; + var data = { + "name": name, + "command": command, + "schedule": cron + }; if (id != null || nId != null) { if (id != null) { @@ -195,7 +202,8 @@ class Api { ); } - static Future> saveFile(String name, String content) async { + static Future> saveFile( + String name, String content) async { return await Http.post( Url.saveFile, {"content": content, "name": name}, @@ -260,7 +268,8 @@ class Api { ); } - static Future> moveEnv(String id, int fromIndex, int toIndex) async { + static Future> moveEnv( + String id, int fromIndex, int toIndex) async { return await Http.put( Url.envMove(id), {"fromIndex": fromIndex, "toIndex": toIndex}, @@ -275,10 +284,12 @@ class Api { } static Future>> taskLog() async { - return await Http.get>(Url.taskLog, null, serializationName: Utils.isUpperVersion2_12_2() ? "data" : "dirs"); + return await Http.get>(Url.taskLog, null, + serializationName: Utils.isUpperVersion2_12_2() ? "data" : "dirs"); } - static Future> taskLogDetail(String name, String path) async { + static Future> taskLogDetail( + String name, String path) async { if (Utils.isUpperVersion2_13_0()) { return await Http.get( Url.taskLogDetail + name + "?path=" + path, @@ -300,7 +311,8 @@ class Api { ); } - static Future> updateScript(String name, String path, String content) async { + static Future> updateScript( + String name, String path, String content) async { return await Http.put( Url.scriptDetail, { @@ -311,7 +323,8 @@ class Api { ); } - static Future> delScript(String name, String path) async { + static Future> delScript( + String name, String path) async { return await Http.delete( Url.scriptDetail, { @@ -321,7 +334,8 @@ class Api { ); } - static Future> scriptDetail(String name, String? path) async { + static Future> scriptDetail( + String name, String? path) async { return await Http.get( Url.scriptDetail + name, { @@ -330,7 +344,8 @@ class Api { ); } - static Future>> dependencies(String type) async { + static Future>> dependencies( + String type) async { return await Http.get>( Url.dependencies, { @@ -339,7 +354,8 @@ class Api { ); } - static Future> dependencyReinstall(String id) async { + static Future> dependencyReinstall( + String id) async { return await Http.put( Url.dependencies, [id], @@ -353,7 +369,8 @@ class Api { ); } - static Future> addDependency(String name, int type) async { + static Future> addDependency( + String name, int type) async { return await Http.post( Url.dependencies, [ @@ -365,7 +382,8 @@ class Api { ); } - static Future> addScript(String name, String path, String content) async { + static Future> addScript( + String name, String path, String content) async { return await Http.post( Url.addScript, { diff --git a/lib/base/http/http.dart b/lib/base/http/http.dart index 52c5dbb..915cd0a 100644 --- a/lib/base/http/http.dart +++ b/lib/base/http/http.dart @@ -122,7 +122,8 @@ class Http { if (!pushedLoginPage) { "身份已过期,请重新登录".toast(); pushedLoginPage = true; - navigatorState.currentState?.pushNamedAndRemoveUntil(Routes.routeLogin, (route) => false); + navigatorState.currentState + ?.pushNamedAndRemoveUntil(Routes.routeLogin, (route) => false); } } @@ -136,9 +137,15 @@ class Http { } if (e.response != null && e.response!.data != null) { - return HttpResponse(success: false, message: e.response?.data["message"] ?? e.message, code: e.response?.data["code"] ?? 0); + return HttpResponse( + success: false, + message: e.response?.data["message"] ?? e.message, + code: e.response?.data["code"] ?? 0); } else { - return HttpResponse(success: false, message: e.message, code: e.response?.statusCode ?? 0); + return HttpResponse( + success: false, + message: e.message, + code: e.response?.statusCode ?? 0); } } @@ -223,7 +230,8 @@ class HttpResponse { late int code; T? bean; - HttpResponse({required this.success, this.message, required this.code, this.bean}); + HttpResponse( + {required this.success, this.message, required this.code, this.bean}); } class DeserializeAction { diff --git a/lib/base/http/token_interceptor.dart b/lib/base/http/token_interceptor.dart index cb58241..821e618 100644 --- a/lib/base/http/token_interceptor.dart +++ b/lib/base/http/token_interceptor.dart @@ -7,8 +7,7 @@ import '../userinfo_viewmodel.dart'; class TokenInterceptor extends Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { - options.headers["User-Agent"] = - "qinglong_client"; + options.headers["User-Agent"] = "qinglong_client"; options.headers["Content-Type"] = "application/json;charset=UTF-8"; diff --git a/lib/base/http/url.dart b/lib/base/http/url.dart index 47a846d..a96842f 100644 --- a/lib/base/http/url.dart +++ b/lib/base/http/url.dart @@ -14,70 +14,127 @@ class Url { static const updatePassword = "/api/user"; - static get tasks => getIt().useSecretLogined ? "/open/crons" : "/api/crons"; + static get tasks => getIt().useSecretLogined + ? "/open/crons" + : "/api/crons"; - static get runTasks => getIt().useSecretLogined ? "/open/crons/run" : "/api/crons/run"; + static get runTasks => getIt().useSecretLogined + ? "/open/crons/run" + : "/api/crons/run"; - static get stopTasks => getIt().useSecretLogined ? "/open/crons/stop" : "/api/crons/stop"; + static get stopTasks => getIt().useSecretLogined + ? "/open/crons/stop" + : "/api/crons/stop"; - static get taskDetail => getIt().useSecretLogined ? "/open/crons/" : "/api/crons/"; + static get taskDetail => getIt().useSecretLogined + ? "/open/crons/" + : "/api/crons/"; - static get addTask => getIt().useSecretLogined ? "/open/crons" : "/api/crons"; + static get addTask => getIt().useSecretLogined + ? "/open/crons" + : "/api/crons"; - static get pinTask => getIt().useSecretLogined ? "/open/crons/pin" : "/api/crons/pin"; + static get pinTask => getIt().useSecretLogined + ? "/open/crons/pin" + : "/api/crons/pin"; - static get unpinTask => getIt().useSecretLogined ? "/open/crons/unpin" : "/api/crons/unpin"; + static get unpinTask => getIt().useSecretLogined + ? "/open/crons/unpin" + : "/api/crons/unpin"; - static get enableTask => getIt().useSecretLogined ? "/open/crons/enable" : "/api/crons/enable"; + static get enableTask => getIt().useSecretLogined + ? "/open/crons/enable" + : "/api/crons/enable"; - static get disableTask => getIt().useSecretLogined ? "/open/crons/disable" : "/api/crons/disable"; + static get disableTask => getIt().useSecretLogined + ? "/open/crons/disable" + : "/api/crons/disable"; - static get files => getIt().useSecretLogined ? "/open/configs/files" : "/api/configs/files"; + static get files => getIt().useSecretLogined + ? "/open/configs/files" + : "/api/configs/files"; - static get configContent => getIt().useSecretLogined ? "/open/configs/" : "/api/configs/"; + static get configContent => getIt().useSecretLogined + ? "/open/configs/" + : "/api/configs/"; - static get saveFile => getIt().useSecretLogined ? "/open/configs/save" : "/api/configs/save"; + static get saveFile => getIt().useSecretLogined + ? "/open/configs/save" + : "/api/configs/save"; - static get envs => getIt().useSecretLogined ? "/open/envs" : "/api/envs"; + static get envs => + getIt().useSecretLogined ? "/open/envs" : "/api/envs"; - static get addEnv => getIt().useSecretLogined ? "/open/envs" : "/api/envs"; + static get addEnv => + getIt().useSecretLogined ? "/open/envs" : "/api/envs"; - static get delEnv => getIt().useSecretLogined ? "/open/envs" : "/api/envs"; + static get delEnv => + getIt().useSecretLogined ? "/open/envs" : "/api/envs"; - static get disableEnvs => getIt().useSecretLogined ? "/open/envs/disable" : "/api/envs/disable"; + static get disableEnvs => getIt().useSecretLogined + ? "/open/envs/disable" + : "/api/envs/disable"; - static get enableEnvs => getIt().useSecretLogined ? "/open/envs/enable" : "/api/envs/enable"; + static get enableEnvs => getIt().useSecretLogined + ? "/open/envs/enable" + : "/api/envs/enable"; - static get loginLog => getIt().useSecretLogined ? "/open/user/login-log" : "/api/user/login-log"; + static get loginLog => getIt().useSecretLogined + ? "/open/user/login-log" + : "/api/user/login-log"; - static get taskLog => getIt().useSecretLogined ? "/open/logs" : "/api/logs"; + static get taskLog => + getIt().useSecretLogined ? "/open/logs" : "/api/logs"; - static get taskLogDetail => getIt().useSecretLogined ? "/open/logs/" : "/api/logs/"; + static get taskLogDetail => getIt().useSecretLogined + ? "/open/logs/" + : "/api/logs/"; - static get scripts => getIt().useSecretLogined ? "/open/scripts/files" : "/api/scripts/files"; + static get scripts => getIt().useSecretLogined + ? "/open/scripts/files" + : "/api/scripts/files"; - static get scripts2 => getIt().useSecretLogined ? "/open/scripts" : "/api/scripts"; + static get scripts2 => getIt().useSecretLogined + ? "/open/scripts" + : "/api/scripts"; - static get scriptUpdate => getIt().useSecretLogined ? "/open/scripts" : "/api/scripts"; + static get scriptUpdate => getIt().useSecretLogined + ? "/open/scripts" + : "/api/scripts"; - static get scriptDetail => getIt().useSecretLogined ? "/open/scripts/" : "/api/scripts/"; + static get scriptDetail => getIt().useSecretLogined + ? "/open/scripts/" + : "/api/scripts/"; - static get dependencies => getIt().useSecretLogined ? "/open/dependencies" : "/api/dependencies"; + static get dependencies => getIt().useSecretLogined + ? "/open/dependencies" + : "/api/dependencies"; - static get addScript => getIt().useSecretLogined ? "/open/scripts" : "/api/scripts"; + static get addScript => getIt().useSecretLogined + ? "/open/scripts" + : "/api/scripts"; - static get dependencyReinstall => getIt().useSecretLogined ? "/open/dependencies/reinstall" : "/api/dependencies/reinstall"; + static get dependencyReinstall => getIt().useSecretLogined + ? "/open/dependencies/reinstall" + : "/api/dependencies/reinstall"; static intimeLog(String cronId) { - return getIt().useSecretLogined ? "/open/crons/$cronId/log" : "/api/crons/$cronId/log"; + return getIt().useSecretLogined + ? "/open/crons/$cronId/log" + : "/api/crons/$cronId/log"; } static envMove(String envId) { - return getIt().useSecretLogined ? "/open/envs/$envId/move" : "/api/envs/$envId/move"; + return getIt().useSecretLogined + ? "/open/envs/$envId/move" + : "/api/envs/$envId/move"; } static bool inWhiteList(String path) { - if (path == login || path == loginByClientId || path == loginTwo || path == loginOld) { + if (path == login || + path == loginByClientId || + path == loginTwo || + path == loginOld) { return true; } return false; diff --git a/lib/base/routes.dart b/lib/base/routes.dart index d0b5293..b9425b2 100644 --- a/lib/base/routes.dart +++ b/lib/base/routes.dart @@ -71,7 +71,8 @@ class Routes { return MaterialPageRoute(builder: (context) => const AddTaskPage()); } case routeAddDependency: - return MaterialPageRoute(builder: (context) => const AddDependencyPage()); + return MaterialPageRoute( + builder: (context) => const AddDependencyPage()); case routeAddEnv: if (settings.arguments != null) { return MaterialPageRoute( diff --git a/lib/base/ui/ql_context_menu.dart b/lib/base/ui/ql_context_menu.dart index ea3c325..1e73d68 100644 --- a/lib/base/ui/ql_context_menu.dart +++ b/lib/base/ui/ql_context_menu.dart @@ -5,7 +5,8 @@ import 'dart:math' as math; import 'dart:ui' as ui; -import 'package:flutter/gestures.dart' show kMinFlingVelocity, kLongPressTimeout; +import 'package:flutter/gestures.dart' + show kMinFlingVelocity, kLongPressTimeout; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -42,7 +43,8 @@ typedef _ContextMenuPreviewBuilderChildless = Widget Function( // paintBounds in global coordinates. Rect _getRect(GlobalKey globalKey) { assert(globalKey.currentContext != null); - final RenderBox renderBoxContainer = globalKey.currentContext!.findRenderObject()! as RenderBox; + final RenderBox renderBoxContainer = + globalKey.currentContext!.findRenderObject()! as RenderBox; final Offset containerOffset = renderBoxContainer.localToGlobal( renderBoxContainer.paintBounds.topLeft, ); @@ -194,7 +196,8 @@ class QlCupertinoContextMenu extends StatefulWidget { State createState() => _QlCupertinoContextMenuState(); } -class _QlCupertinoContextMenuState extends State with TickerProviderStateMixin { +class _QlCupertinoContextMenuState extends State + with TickerProviderStateMixin { final GlobalKey _childGlobalKey = GlobalKey(); bool _childHidden = false; @@ -227,7 +230,8 @@ class _QlCupertinoContextMenuState extends State with Ti final double screenWidth = MediaQuery.of(context).size.width; final double center = screenWidth / 2; - final bool centerDividesChild = childRect.left < center && childRect.right > center; + final bool centerDividesChild = + childRect.left < center && childRect.right > center; final double distanceFromCenter = (center - childRect.center.dx).abs(); if (centerDividesChild && distanceFromCenter <= childRect.width / 4) { return _ContextMenuLocation.center; @@ -318,7 +322,8 @@ class _QlCupertinoContextMenuState extends State with Ti _openController.reverse(); } else { if (_openController.isDismissed) { - Navigator.of(context).pushNamed(Routes.routeTaskDetail, arguments: widget.bean); + Navigator.of(context) + .pushNamed(Routes.routeTaskDetail, arguments: widget.bean); } } } @@ -419,7 +424,8 @@ class _DecoyChild extends StatefulWidget { _DecoyChildState createState() => _DecoyChildState(); } -class _DecoyChildState extends State<_DecoyChild> with TickerProviderStateMixin { +class _DecoyChildState extends State<_DecoyChild> + with TickerProviderStateMixin { // TODO(justinmc): Dark mode support. // See https://github.com/flutter/flutter/issues/43211. static const Color _lightModeMaskColor = Color(0xFF888888); @@ -481,7 +487,9 @@ class _DecoyChildState extends State<_DecoyChild> with TickerProviderStateMixin } Widget _buildAnimation(BuildContext context, Widget? child) { - final Color color = widget.controller.status == AnimationStatus.reverse ? _masklessColor : _mask.value; + final Color color = widget.controller.status == AnimationStatus.reverse + ? _masklessColor + : _mask.value; return Positioned.fromRect( rect: _rect.value!, child: ShaderMask( @@ -538,7 +546,8 @@ class _ContextMenuRoute extends PopupRoute { // The duration of the transition used when a modal popup is shown. Eyeballed // from a physical device running iOS 13.1.2. - static const Duration _kModalPopupTransitionDuration = Duration(milliseconds: 335); + static const Duration _kModalPopupTransitionDuration = + Duration(milliseconds: 335); final List _actions; final _ContextMenuPreviewBuilderChildless? _builder; @@ -562,7 +571,8 @@ class _ContextMenuRoute extends PopupRoute { static final RectTween _rectTween = RectTween(); static final Animatable _rectAnimatable = _rectTween.chain(_curve); static final RectTween _rectTweenReverse = RectTween(); - static final Animatable _rectAnimatableReverse = _rectTweenReverse.chain( + static final Animatable _rectAnimatableReverse = + _rectTweenReverse.chain( _curveReverse, ); static final RectTween _sheetRectTween = RectTween(); @@ -573,10 +583,12 @@ class _ContextMenuRoute extends PopupRoute { _curveReverse, ); static final Tween _sheetScaleTween = Tween(); - static final Animatable _sheetScaleAnimatable = _sheetScaleTween.chain( + static final Animatable _sheetScaleAnimatable = + _sheetScaleTween.chain( _curve, ); - static final Animatable _sheetScaleAnimatableReverse = _sheetScaleTween.chain( + static final Animatable _sheetScaleAnimatableReverse = + _sheetScaleTween.chain( _curveReverse, ); final Tween _opacityTween = Tween(begin: 0.0, end: 1.0); @@ -611,7 +623,8 @@ class _ContextMenuRoute extends PopupRoute { // Get the alignment for the _ContextMenuSheet's Transform.scale based on the // contextMenuLocation. - static AlignmentDirectional getSheetAlignment(_ContextMenuLocation contextMenuLocation) { + static AlignmentDirectional getSheetAlignment( + _ContextMenuLocation contextMenuLocation) { switch (contextMenuLocation) { case _ContextMenuLocation.center: return AlignmentDirectional.topCenter; @@ -623,17 +636,27 @@ class _ContextMenuRoute extends PopupRoute { } // The place to start the sheetRect animation from. - static Rect _getSheetRectBegin(Orientation? orientation, _ContextMenuLocation contextMenuLocation, Rect childRect, Rect sheetRect) { + static Rect _getSheetRectBegin( + Orientation? orientation, + _ContextMenuLocation contextMenuLocation, + Rect childRect, + Rect sheetRect) { switch (contextMenuLocation) { case _ContextMenuLocation.center: - final Offset target = orientation == Orientation.portrait ? childRect.bottomCenter : childRect.topCenter; + final Offset target = orientation == Orientation.portrait + ? childRect.bottomCenter + : childRect.topCenter; final Offset centered = target - Offset(sheetRect.width / 2, 0.0); return centered & sheetRect.size; case _ContextMenuLocation.right: - final Offset target = orientation == Orientation.portrait ? childRect.bottomRight : childRect.topRight; + final Offset target = orientation == Orientation.portrait + ? childRect.bottomRight + : childRect.topRight; return (target - Offset(sheetRect.width, 0.0)) & sheetRect.size; case _ContextMenuLocation.left: - final Offset target = orientation == Orientation.portrait ? childRect.bottomLeft : childRect.topLeft; + final Offset target = orientation == Orientation.portrait + ? childRect.bottomLeft + : childRect.topLeft; return target & sheetRect.size; } } @@ -651,7 +674,9 @@ class _ContextMenuRoute extends PopupRoute { // Take measurements on the child and _ContextMenuSheet and update the // animation tweens to match. void _updateTweenRects() { - final Rect childRect = _scale == null ? _getRect(_childGlobalKey) : _getScaledRect(_childGlobalKey, _scale!); + final Rect childRect = _scale == null + ? _getRect(_childGlobalKey) + : _getScaledRect(_childGlobalKey, _scale!); _rectTween.begin = _previousChildRect; _rectTween.end = childRect; @@ -725,7 +750,8 @@ class _ContextMenuRoute extends PopupRoute { } @override - Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + Widget buildPage(BuildContext context, Animation animation, + Animation secondaryAnimation) { // This is usually used to build the "page", which is then passed to // buildTransitions as child, the idea being that buildTransitions will // animate the entire page into the scene. In the case of _ContextMenuRoute, @@ -735,7 +761,8 @@ class _ContextMenuRoute extends PopupRoute { } @override - Widget buildTransitions(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { + Widget buildTransitions(BuildContext context, Animation animation, + Animation secondaryAnimation, Widget child) { return OrientationBuilder( builder: (BuildContext context, Orientation orientation) { _lastOrientation = orientation; @@ -744,9 +771,15 @@ class _ContextMenuRoute extends PopupRoute { // they're movable. if (!animation.isCompleted) { final bool reverse = animation.status == AnimationStatus.reverse; - final Rect rect = reverse ? _rectAnimatableReverse.evaluate(animation)! : _rectAnimatable.evaluate(animation)!; - final Rect sheetRect = reverse ? _sheetRectAnimatableReverse.evaluate(animation)! : _sheetRectAnimatable.evaluate(animation)!; - final double sheetScale = reverse ? _sheetScaleAnimatableReverse.evaluate(animation) : _sheetScaleAnimatable.evaluate(animation); + final Rect rect = reverse + ? _rectAnimatableReverse.evaluate(animation)! + : _rectAnimatable.evaluate(animation)!; + final Rect sheetRect = reverse + ? _sheetRectAnimatableReverse.evaluate(animation)! + : _sheetRectAnimatable.evaluate(animation)!; + final double sheetScale = reverse + ? _sheetScaleAnimatableReverse.evaluate(animation) + : _sheetScaleAnimatable.evaluate(animation); return Stack( children: [ Positioned.fromRect( @@ -818,7 +851,8 @@ class _ContextMenuRouteStatic extends StatefulWidget { _ContextMenuRouteStaticState createState() => _ContextMenuRouteStaticState(); } -class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with TickerProviderStateMixin { +class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> + with TickerProviderStateMixin { // The child is scaled down as it is dragged down until it hits this minimum // value. static const double _kMinScale = 0.8; @@ -838,7 +872,8 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T late Animation _sheetOpacityAnimation; // The scale of the child changes as a function of the distance it is dragged. - static double _getScale(Orientation orientation, double maxDragDistance, double dy) { + static double _getScale( + Orientation orientation, double maxDragDistance, double dy) { final double dyDirectional = dy <= 0.0 ? dy : -dy; return math.max( _kMinScale, @@ -859,11 +894,13 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T // If flung, animate a bit before handling the potential dismiss. if (details.velocity.pixelsPerSecond.dy.abs() >= kMinFlingVelocity) { final bool flingIsAway = details.velocity.pixelsPerSecond.dy > 0; - final double finalPosition = flingIsAway ? _moveAnimation.value.dy + 100.0 : 0.0; + final double finalPosition = + flingIsAway ? _moveAnimation.value.dy + 100.0 : 0.0; if (flingIsAway && _sheetController.status != AnimationStatus.forward) { _sheetController.forward(); - } else if (!flingIsAway && _sheetController.status != AnimationStatus.reverse) { + } else if (!flingIsAway && + _sheetController.status != AnimationStatus.reverse) { _sheetController.reverse(); } @@ -918,21 +955,30 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T widget.onDismiss!(context, _lastScale, _sheetOpacityAnimation.value); } - Alignment _getChildAlignment(Orientation orientation, _ContextMenuLocation contextMenuLocation) { + Alignment _getChildAlignment( + Orientation orientation, _ContextMenuLocation contextMenuLocation) { switch (contextMenuLocation) { case _ContextMenuLocation.center: - return orientation == Orientation.portrait ? Alignment.bottomCenter : Alignment.topRight; + return orientation == Orientation.portrait + ? Alignment.bottomCenter + : Alignment.topRight; case _ContextMenuLocation.right: - return orientation == Orientation.portrait ? Alignment.bottomCenter : Alignment.topLeft; + return orientation == Orientation.portrait + ? Alignment.bottomCenter + : Alignment.topLeft; case _ContextMenuLocation.left: - return orientation == Orientation.portrait ? Alignment.bottomCenter : Alignment.topRight; + return orientation == Orientation.portrait + ? Alignment.bottomCenter + : Alignment.topRight; } } void _setDragOffset(Offset dragOffset) { // Allow horizontal and negative vertical movement, but damp it. final double endX = _kPadding * dragOffset.dx / _kDamping; - final double endY = dragOffset.dy >= 0.0 ? dragOffset.dy : _kPadding * dragOffset.dy / _kDamping; + final double endY = dragOffset.dy >= 0.0 + ? dragOffset.dy + : _kPadding * dragOffset.dy / _kDamping; setState(() { _dragOffset = dragOffset; _moveAnimation = Tween( @@ -949,9 +995,13 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T ); // Fade the _ContextMenuSheet out or in, if needed. - if (_lastScale <= _kSheetScaleThreshold && _sheetController.status != AnimationStatus.forward && _sheetScaleAnimation.value != 0.0) { + if (_lastScale <= _kSheetScaleThreshold && + _sheetController.status != AnimationStatus.forward && + _sheetScaleAnimation.value != 0.0) { _sheetController.forward(); - } else if (_lastScale > _kSheetScaleThreshold && _sheetController.status != AnimationStatus.reverse && _sheetScaleAnimation.value != 1.0) { + } else if (_lastScale > _kSheetScaleThreshold && + _sheetController.status != AnimationStatus.reverse && + _sheetScaleAnimation.value != 1.0) { _sheetController.reverse(); } }); @@ -960,7 +1010,8 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T // The order and alignment of the _ContextMenuSheet and the child depend on // both the orientation of the screen as well as the position on the screen of // the original child. - List _getChildren(Orientation orientation, _ContextMenuLocation contextMenuLocation) { + List _getChildren( + Orientation orientation, _ContextMenuLocation contextMenuLocation) { final Expanded child = Expanded( child: Align( alignment: _getChildAlignment( @@ -995,7 +1046,9 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T case _ContextMenuLocation.center: return [child, spacer, sheet]; case _ContextMenuLocation.right: - return orientation == Orientation.portrait ? [child, spacer, sheet] : [sheet, spacer, child]; + return orientation == Orientation.portrait + ? [child, spacer, sheet] + : [sheet, spacer, child]; case _ContextMenuLocation.left: return [child, spacer, sheet]; } @@ -1004,7 +1057,8 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T // Build the animation for the _ContextMenuSheet. Widget _buildSheetAnimation(BuildContext context, Widget? child) { return Transform.scale( - alignment: _ContextMenuRoute.getSheetAlignment(widget.contextMenuLocation), + alignment: + _ContextMenuRoute.getSheetAlignment(widget.contextMenuLocation), scale: _sheetScaleAnimation.value, child: FadeTransition( opacity: _sheetOpacityAnimation, diff --git a/lib/base/ui/search_cell.dart b/lib/base/ui/search_cell.dart index bc4aacc..122627b 100644 --- a/lib/base/ui/search_cell.dart +++ b/lib/base/ui/search_cell.dart @@ -17,7 +17,6 @@ class SearchCell extends ConsumerStatefulWidget { } class _SearchCellState extends ConsumerState { - @override void initState() { super.initState(); @@ -35,9 +34,7 @@ class _SearchCellState extends ConsumerState { ), onSuffixTap: () { widget.controller.text = ""; - setState(() { - - }); + setState(() {}); }, controller: widget.controller, padding: const EdgeInsets.symmetric( diff --git a/lib/base/ui/source_code_view.dart b/lib/base/ui/source_code_view.dart index 4043cd6..4c41ab1 100644 --- a/lib/base/ui/source_code_view.dart +++ b/lib/base/ui/source_code_view.dart @@ -29,9 +29,8 @@ class SourceCodeView extends StatefulWidget { this.syntaxHighlighterStyle, }) : super(key: key); - String? get codeLink => codeLinkPrefix == null - ? null - : '$codeLinkPrefix/$filePath'; + String? get codeLink => + codeLinkPrefix == null ? null : '$codeLinkPrefix/$filePath'; @override _SourceCodeViewState createState() { diff --git a/lib/base/ui/syntax_highlighter.dart b/lib/base/ui/syntax_highlighter.dart index 101ca92..7c375dd 100644 --- a/lib/base/ui/syntax_highlighter.dart +++ b/lib/base/ui/syntax_highlighter.dart @@ -17,7 +17,10 @@ class SyntaxHighlighterStyle { this.constantStyle}); static SyntaxHighlighterStyle lightThemeStyle() => SyntaxHighlighterStyle( - baseStyle: const TextStyle(color: const Color(0xFF000000),height: 1,), + baseStyle: const TextStyle( + color: const Color(0xFF000000), + height: 1, + ), numberStyle: const TextStyle(color: const Color(0xFF1565C0)), commentStyle: const TextStyle(color: const Color(0xFF9E9E9E)), keywordStyle: const TextStyle(color: const Color(0xFF9C27B0)), diff --git a/lib/base/userinfo_viewmodel.dart b/lib/base/userinfo_viewmodel.dart index 66c0911..7b92fc9 100644 --- a/lib/base/userinfo_viewmodel.dart +++ b/lib/base/userinfo_viewmodel.dart @@ -26,7 +26,8 @@ class UserInfoViewModel { _useSecertLogined = SpUtil.getBool(spSecretLogined, defValue: false); _host = SpUtil.getString(spHost, defValue: ''); - List? tempList = jsonDecode(SpUtil.getString(spLoginHistory, defValue: '[]')); + List? tempList = + jsonDecode(SpUtil.getString(spLoginHistory, defValue: '[]')); if (tempList != null && tempList.isNotEmpty) { for (Map value in tempList) { @@ -40,7 +41,8 @@ class UserInfoViewModel { SpUtil.putString(spUserInfo, token); } - void updateUserName(String host, String userName, String password, bool secretLogin) { + void updateUserName( + String host, String userName, String password, bool secretLogin) { updateHost(host); _useSecretLogin(secretLogin); _userName = userName; @@ -93,7 +95,13 @@ class UserInfoViewModel { historyAccounts.removeWhere((element) => element.host == _host); - historyAccounts.insert(0, UserInfoBean(userName: _userName, password: _passWord, useSecretLogined: _useSecertLogined, host: _host)); + historyAccounts.insert( + 0, + UserInfoBean( + userName: _userName, + password: _passWord, + useSecretLogined: _useSecertLogined, + host: _host)); while (historyAccounts.length > 3) { historyAccounts.removeLast(); @@ -117,7 +125,8 @@ class UserInfoBean { bool useSecretLogined = false; String? host; - UserInfoBean({this.userName, this.password, this.useSecretLogined = false, this.host}); + UserInfoBean( + {this.userName, this.password, this.useSecretLogined = false, this.host}); UserInfoBean.fromJson(Map json) { userName = json['userName']; diff --git a/lib/json.jc.dart b/lib/json.jc.dart index cf338fb..9c82c48 100644 --- a/lib/json.jc.dart +++ b/lib/json.jc.dart @@ -11,10 +11,8 @@ import 'package:qinglong_app/module/others/scripts/script_bean.dart'; import 'package:qinglong_app/module/others/task_log/task_log_bean.dart'; import 'package:qinglong_app/module/task/task_bean.dart'; - class JsonConversion$Json { - - static M fromJson(dynamic json) { + static M fromJson(dynamic json) { if (json is List) { return _getListChildType(json); } else { @@ -23,93 +21,104 @@ class JsonConversion$Json { } static M _fromJsonSingle(dynamic json) { - String type = M.toString(); - if(type == (ConfigBean).toString()){ - return ConfigBean.jsonConversion(json) as M; + if (type == (ConfigBean).toString()) { + return ConfigBean.jsonConversion(json) as M; } - - if(type == (EnvBean).toString()){ - return EnvBean.jsonConversion(json) as M; + + if (type == (EnvBean).toString()) { + return EnvBean.jsonConversion(json) as M; } - - if(type == (SystemBean).toString()){ - return SystemBean.jsonConversion(json) as M; + + if (type == (SystemBean).toString()) { + return SystemBean.jsonConversion(json) as M; } - - if(type == (LoginBean).toString()){ - return LoginBean.jsonConversion(json) as M; + + if (type == (LoginBean).toString()) { + return LoginBean.jsonConversion(json) as M; } - - if(type == (UserBean).toString()){ - return UserBean.jsonConversion(json) as M; + + if (type == (UserBean).toString()) { + return UserBean.jsonConversion(json) as M; } - - if(type == (DependencyBean).toString()){ - return DependencyBean.jsonConversion(json) as M; + + if (type == (DependencyBean).toString()) { + return DependencyBean.jsonConversion(json) as M; } - - if(type == (LoginLogBean).toString()){ - return LoginLogBean.jsonConversion(json) as M; + + if (type == (LoginLogBean).toString()) { + return LoginLogBean.jsonConversion(json) as M; } - - if(type == (ScriptBean).toString()){ - return ScriptBean.jsonConversion(json) as M; + + if (type == (ScriptBean).toString()) { + return ScriptBean.jsonConversion(json) as M; } - - if(type == (TaskLogBean).toString()){ - return TaskLogBean.jsonConversion(json) as M; + + if (type == (TaskLogBean).toString()) { + return TaskLogBean.jsonConversion(json) as M; } - - if(type == (TaskBean).toString()){ - return TaskBean.jsonConversion(json) as M; + + if (type == (TaskBean).toString()) { + return TaskBean.jsonConversion(json) as M; } - + throw Exception("not found"); } static M _getListChildType(List data) { - if([] is M){ - return data.map((e) => ConfigBean.jsonConversion(e)).toList() as M; + if ([] is M) { + return data.map((e) => ConfigBean.jsonConversion(e)).toList() + as M; } - - if([] is M){ + + if ([] is M) { return data.map((e) => EnvBean.jsonConversion(e)).toList() as M; } - - if([] is M){ - return data.map((e) => SystemBean.jsonConversion(e)).toList() as M; + + if ([] is M) { + return data.map((e) => SystemBean.jsonConversion(e)).toList() + as M; } - - if([] is M){ - return data.map((e) => LoginBean.jsonConversion(e)).toList() as M; + + if ([] is M) { + return data.map((e) => LoginBean.jsonConversion(e)).toList() + as M; } - - if([] is M){ - return data.map((e) => UserBean.jsonConversion(e)).toList() as M; + + if ([] is M) { + return data.map((e) => UserBean.jsonConversion(e)).toList() + as M; } - - if([] is M){ - return data.map((e) => DependencyBean.jsonConversion(e)).toList() as M; + + if ([] is M) { + return data + .map((e) => DependencyBean.jsonConversion(e)) + .toList() as M; } - - if([] is M){ - return data.map((e) => LoginLogBean.jsonConversion(e)).toList() as M; + + if ([] is M) { + return data + .map((e) => LoginLogBean.jsonConversion(e)) + .toList() as M; } - - if([] is M){ - return data.map((e) => ScriptBean.jsonConversion(e)).toList() as M; + + if ([] is M) { + return data.map((e) => ScriptBean.jsonConversion(e)).toList() + as M; } - - if([] is M){ - return data.map((e) => TaskLogBean.jsonConversion(e)).toList() as M; + + if ([] is M) { + return data + .map((e) => TaskLogBean.jsonConversion(e)) + .toList() as M; } - - if([] is M){ - return data.map((e) => TaskBean.jsonConversion(e)).toList() as M; + + if ([] is M) { + return data.map((e) => TaskBean.jsonConversion(e)).toList() + as M; } - + throw Exception("not found"); } } diff --git a/lib/main.dart b/lib/main.dart index ef71de6..c24a918 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -41,7 +41,8 @@ void main() async { ), ); if (Platform.isAndroid) { - SystemUiOverlayStyle style = const SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemUiOverlayStyle style = + const SystemUiOverlayStyle(statusBarColor: Colors.transparent); SystemChrome.setSystemUIOverlayStyle(style); } } @@ -62,7 +63,8 @@ class QlAppState extends ConsumerState { FocusScope.of(context).requestFocus(FocusNode()); }, child: MediaQuery( - data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith( + data: + MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith( textScaleFactor: 1, ), child: MaterialApp( @@ -87,7 +89,9 @@ class QlAppState extends ConsumerState { if (!kReleaseMode) { showDebugBtn(context); } - return getIt().isLogined() ? const HomePage() : const LoginPage(); + return getIt().isLogined() + ? const HomePage() + : const LoginPage(); }, ), // home: LoginPage(), diff --git a/lib/module/change_account_page.dart b/lib/module/change_account_page.dart index 77343c6..87474a1 100644 --- a/lib/module/change_account_page.dart +++ b/lib/module/change_account_page.dart @@ -64,13 +64,17 @@ class _ChangeAccountPageState extends ConsumerState { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { - if (index == getIt().historyAccounts.length) { + if (index == + getIt().historyAccounts.length) { return addAccount(); } return ClipRRect( borderRadius: BorderRadius.circular(10), child: Container( - color: ref.watch(themeProvider).themeColor.settingBordorColor(), + color: ref + .watch(themeProvider) + .themeColor + .settingBordorColor(), child: buildCell(index), ), ); @@ -80,7 +84,8 @@ class _ChangeAccountPageState extends ConsumerState { height: 10, ); }, - itemCount: getIt().historyAccounts.length + 1), + itemCount: + getIt().historyAccounts.length + 1), ), ], ), @@ -108,31 +113,34 @@ class _ChangeAccountPageState extends ConsumerState { ), 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), - ), - ) + 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()), + ? SizedBox( + width: 15, + height: 15, + child: CircularProgressIndicator( + strokeWidth: 2, + color: ref.watch(themeProvider).primaryColor, + ), + ) + : const SizedBox.shrink()), ); - if (getIt().historyAccounts[index].host == getIt().host) { + if (getIt().historyAccounts[index].host == + getIt().host) { return child; } @@ -146,7 +154,8 @@ class _ChangeAccountPageState extends ConsumerState { backgroundColor: Colors.red, flex: 1, onPressed: (_) { - getIt().removeHistoryAccount(getIt().historyAccounts[index].host); + getIt().removeHistoryAccount( + getIt().historyAccounts[index].host); setState(() {}); }, foregroundColor: Colors.white, @@ -181,7 +190,8 @@ class _ChangeAccountPageState extends ConsumerState { void dealLoginResponse(int response) { if (response == LoginHelper.success) { - Navigator.of(context).pushNamedAndRemoveUntil(Routes.routeHomePage, (_) => false); + Navigator.of(context) + .pushNamedAndRemoveUntil(Routes.routeHomePage, (_) => false); } else if (response == LoginHelper.failed) { loginFailed(); } else { @@ -201,58 +211,58 @@ class _ChangeAccountPageState extends ConsumerState { 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", + 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, + ), ), - autofocus: true, - ), + ], ), - ], - ), - actions: [ - CupertinoDialogAction( - child: const Text( - "取消", - style: TextStyle( - color: Color(0xff999999), + actions: [ + CupertinoDialogAction( + child: const Text( + "取消", + style: TextStyle( + color: Color(0xff999999), + ), + ), + onPressed: () { + Navigator.of(context).pop(); + }, ), - ), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - CupertinoDialogAction( - child: Text( - "确定", - style: TextStyle( - color: ref.watch(themeProvider).primaryColor, + 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(); + } + }, ), - ), - onPressed: () async { - Navigator.of(context).pop(true); - if (helper != null) { - var response = await helper!.loginTwice(twoFact); - dealLoginResponse(response); - } else { - "状态异常".toast(); - } - }, - ), - ], - )).then((value) { + ], + )).then((value) { if (value == null) { isLoginingHost = ""; setState(() {}); @@ -266,7 +276,7 @@ class _ChangeAccountPageState extends ConsumerState { onTap: () { Navigator.of(context).pushNamedAndRemoveUntil( Routes.routeLogin, - (_) => false, + (_) => false, arguments: true, ); }, diff --git a/lib/module/config/config_edit_page.dart b/lib/module/config/config_edit_page.dart index 82f54e0..bfad5f8 100644 --- a/lib/module/config/config_edit_page.dart +++ b/lib/module/config/config_edit_page.dart @@ -47,8 +47,8 @@ class _ConfigEditPageState extends ConsumerState { }); } - Future notifyICloud(BuildContext context, String? title, String? content) async { - } + Future notifyICloud( + BuildContext context, String? title, String? content) async {} @override Widget build(BuildContext context) { @@ -60,7 +60,8 @@ class _ConfigEditPageState extends ConsumerState { }, theme: ref.watch(themeProvider).themeColor.codeEditorTheme(), stringMap: { - "export": const TextStyle(fontWeight: FontWeight.normal, color: Color(0xff6B2375)), + "export": const TextStyle( + fontWeight: FontWeight.normal, color: Color(0xff6B2375)), }, ); return Scaffold( @@ -122,10 +123,10 @@ class _ConfigEditPageState extends ConsumerState { ...operateList .map( (e) => PopupMenuItem( - child: Text(e), - value: e, - ), - ) + child: Text(e), + value: e, + ), + ) .toList(), ], child: const Center( @@ -137,7 +138,8 @@ class _ConfigEditPageState extends ConsumerState { ), InkWell( onTap: () async { - HttpResponse response = await Api.saveFile(widget.title, result); + HttpResponse response = + await Api.saveFile(widget.title, result); await notifyICloud(context, widget.title, result); if (response.success) { "提交成功".toast(); @@ -226,7 +228,8 @@ class _ConfigEditPageState extends ConsumerState { } } catch (e) {} - TextEditingController controller = TextEditingController(text: defaultValue.replaceAll("\"", "").replaceAll("'", "")); + TextEditingController controller = TextEditingController( + text: defaultValue.replaceAll("\"", "").replaceAll("'", "")); showCupertinoDialog( useRootNavigator: false, context: context, diff --git a/lib/module/config/config_page.dart b/lib/module/config/config_page.dart index 9a9e8cc..e6b38ee 100644 --- a/lib/module/config/config_page.dart +++ b/lib/module/config/config_page.dart @@ -24,7 +24,8 @@ class ConfigPage extends StatefulWidget { ConfigPageState createState() => ConfigPageState(); } -class ConfigPageState extends State with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin { +class ConfigPageState extends State + with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin { int _initIndex = 0; BuildContext? childContext; @@ -89,8 +90,14 @@ class ConfigPageState extends State with SingleTickerProviderStateMi void editMe(WidgetRef ref) { if (childContext == null) return; navigatorState.currentState?.pushNamed(Routes.routeConfigEdit, arguments: { - "title": ref.read(configProvider).list[DefaultTabController.of(childContext!)?.index ?? 0].title, - "content": ref.read(configProvider).content[ref.read(configProvider).list[DefaultTabController.of(childContext!)?.index ?? 0].title] + "title": ref + .read(configProvider) + .list[DefaultTabController.of(childContext!)?.index ?? 0] + .title, + "content": ref.read(configProvider).content[ref + .read(configProvider) + .list[DefaultTabController.of(childContext!)?.index ?? 0] + .title] }).then((value) async { if (value != null && (value as String).isNotEmpty) { await ref.read(configProvider).loadContent(value); @@ -115,7 +122,8 @@ class CodeWidget extends ConsumerStatefulWidget { ConsumerState createState() => _CodeWidgetState(); } -class _CodeWidgetState extends ConsumerState with AutomaticKeepAliveClientMixin { +class _CodeWidgetState extends ConsumerState + with AutomaticKeepAliveClientMixin { CodeController? _codeController; @override @@ -143,7 +151,8 @@ class _CodeWidgetState extends ConsumerState with AutomaticKeepAlive }, theme: ref.watch(themeProvider).themeColor.codeEditorTheme(), stringMap: { - "export": const TextStyle(fontWeight: FontWeight.normal, color: Color(0xff6B2375)), + "export": const TextStyle( + fontWeight: FontWeight.normal, color: Color(0xff6B2375)), }, ); return SafeArea( diff --git a/lib/module/env/add_env_page.dart b/lib/module/env/add_env_page.dart index 70e0ff3..cedebfc 100644 --- a/lib/module/env/add_env_page.dart +++ b/lib/module/env/add_env_page.dart @@ -186,8 +186,12 @@ class _AddEnvPageState extends ConsumerState { envBean.value = _valueController.text; envBean.remarks = _remarkController.text; HttpResponse response = await Api.addEnv( - _nameController.text, _valueController.text, _remarkController.text, - id: envBean.id,nId: envBean.nId,); + _nameController.text, + _valueController.text, + _remarkController.text, + id: envBean.id, + nId: envBean.nId, + ); if (response.success) { (envBean.sId == null) ? "新增成功" : "修改成功".toast(); diff --git a/lib/module/env/env_bean.dart b/lib/module/env/env_bean.dart index d149410..c5f8a86 100644 --- a/lib/module/env/env_bean.dart +++ b/lib/module/env/env_bean.dart @@ -12,7 +12,14 @@ class EnvBean { String? name; String? remarks; - EnvBean({this.value, this.sId, this.created, this.status, this.timestamp, this.name, this.remarks}); + EnvBean( + {this.value, + this.sId, + this.created, + this.status, + this.timestamp, + this.name, + this.remarks}); get nId => _id; @@ -20,7 +27,9 @@ class EnvBean { value = json['value']; id = json['id']; _id = json['_id']; - sId = json.containsKey('_id') ? json['_id'].toString() : (json.containsKey('id') ? json['id'].toString() : ""); + sId = json.containsKey('_id') + ? json['_id'].toString() + : (json.containsKey('id') ? json['id'].toString() : ""); created = int.tryParse(json['created'].toString()); status = json['status']; timestamp = json['timestamp']; diff --git a/lib/module/env/env_detail_page.dart b/lib/module/env/env_detail_page.dart index 28a983f..83a3680 100644 --- a/lib/module/env/env_detail_page.dart +++ b/lib/module/env/env_detail_page.dart @@ -36,7 +36,8 @@ class _TaskDetailPageState extends ConsumerState { behavior: HitTestBehavior.opaque, onTap: () { Navigator.of(context).pop(); - Navigator.of(context).pushNamed(Routes.routeAddEnv, arguments: widget.envBean); + Navigator.of(context) + .pushNamed(Routes.routeAddEnv, arguments: widget.envBean); }, child: Container( padding: const EdgeInsets.symmetric( @@ -225,7 +226,9 @@ class _TaskDetailPageState extends ConsumerState { } void enableTask() async { - await ref.read(envProvider).enableEnv(widget.envBean.sId!, widget.envBean.status!); + await ref + .read(envProvider) + .enableEnv(widget.envBean.sId!, widget.envBean.status!); setState(() {}); } @@ -322,14 +325,16 @@ class EnvDetailCell extends ConsumerWidget { } }, style: TextStyle( - color: ref.watch(themeProvider).themeColor.descColor(), + color: + ref.watch(themeProvider).themeColor.descColor(), fontSize: 14, ), ), ), ) : Expanded( - child: Align(alignment: Alignment.centerRight, child: icon!), + child: + Align(alignment: Alignment.centerRight, child: icon!), ), ], ), diff --git a/lib/module/env/env_page.dart b/lib/module/env/env_page.dart index aee9752..2303f72 100644 --- a/lib/module/env/env_page.dart +++ b/lib/module/env/env_page.dart @@ -83,7 +83,8 @@ class _EnvPageState extends State { ], ) : ReorderableListView( - keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, + keyboardDismissBehavior: + ScrollViewKeyboardDismissBehavior.onDrag, header: searchCell(context, ref), onReorder: (int oldIndex, int newIndex) { if (list.length != model.list.length) { @@ -97,9 +98,11 @@ class _EnvPageState extends State { if (newIndex > oldIndex) { newIndex -= 1; } - final EnvBean item = model.list.removeAt(oldIndex); + final EnvBean item = + model.list.removeAt(oldIndex); model.list.insert(newIndex, item); - model.update(item.sId ?? "", newIndex, oldIndex); + model.update( + item.sId ?? "", newIndex, oldIndex); }, ); }, @@ -145,7 +148,9 @@ class _EnvPageState extends State { child: Text( EnvViewModel.allStr, style: TextStyle( - color: currentState == EnvViewModel.allStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + color: currentState == EnvViewModel.allStr + ? ref.watch(themeProvider).primaryColor + : ref.watch(themeProvider).themeColor.titleColor(), fontSize: 14, ), ), @@ -155,7 +160,9 @@ class _EnvPageState extends State { child: Text( EnvViewModel.enabledStr, style: TextStyle( - color: currentState == EnvViewModel.enabledStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + color: currentState == EnvViewModel.enabledStr + ? ref.watch(themeProvider).primaryColor + : ref.watch(themeProvider).themeColor.titleColor(), fontSize: 14, ), ), @@ -165,8 +172,9 @@ class _EnvPageState extends State { child: Text( EnvViewModel.disabledStr, style: TextStyle( - color: - currentState == EnvViewModel.disabledStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + color: currentState == EnvViewModel.disabledStr + ? ref.watch(themeProvider).primaryColor + : ref.watch(themeProvider).themeColor.titleColor(), fontSize: 14, ), ), @@ -199,7 +207,8 @@ class EnvItemCell extends StatelessWidget { final int index; final WidgetRef ref; - const EnvItemCell(this.bean, this.index, this.ref, {Key? key}) : super(key: key); + const EnvItemCell(this.bean, this.index, this.ref, {Key? key}) + : super(key: key); @override Widget build(BuildContext context) { @@ -212,7 +221,8 @@ class EnvItemCell extends StatelessWidget { SlidableAction( backgroundColor: const Color(0xff5D5E70), onPressed: (_) { - Navigator.of(context).pushNamed(Routes.routeAddEnv, arguments: bean); + Navigator.of(context) + .pushNamed(Routes.routeAddEnv, arguments: bean); }, foregroundColor: Colors.white, icon: CupertinoIcons.pencil_outline, @@ -223,7 +233,9 @@ class EnvItemCell extends StatelessWidget { enableEnv(context); }, foregroundColor: Colors.white, - icon: bean.status == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp, + icon: bean.status == 0 + ? Icons.dnd_forwardslash + : Icons.check_circle_outline_sharp, ), SlidableAction( backgroundColor: const Color(0xffEA4D3E), @@ -245,7 +257,8 @@ class EnvItemCell extends StatelessWidget { color: ref.watch(themeProvider).themeColor.settingBgColor(), child: InkWell( onTap: () { - Navigator.of(context).pushNamed(Routes.routeEnvDetail, arguments: bean); + Navigator.of(context) + .pushNamed(Routes.routeEnvDetail, arguments: bean); }, child: Container( padding: const EdgeInsets.symmetric( @@ -272,13 +285,22 @@ class EnvItemCell extends StatelessWidget { horizontal: 5, ), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(3), - border: Border.all(color: ref.watch(themeProvider).themeColor.descColor(), width: 1), + 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(), + color: ref + .watch(themeProvider) + .themeColor + .descColor(), fontSize: 12, ), ), @@ -299,7 +321,10 @@ class EnvItemCell extends StatelessWidget { maxLines: 1, style: TextStyle( overflow: TextOverflow.ellipsis, - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 16, ), ), @@ -315,7 +340,8 @@ class EnvItemCell extends StatelessWidget { ), ), child: Visibility( - visible: bean.remarks != null && bean.remarks!.isNotEmpty, + visible: bean.remarks != null && + bean.remarks!.isNotEmpty, child: Material( color: Colors.transparent, child: Text( @@ -324,7 +350,10 @@ class EnvItemCell extends StatelessWidget { style: TextStyle( height: 1, overflow: TextOverflow.ellipsis, - color: ref.watch(themeProvider).themeColor.descColor(), + color: ref + .watch(themeProvider) + .themeColor + .descColor(), fontSize: 12, ), ), @@ -358,7 +387,10 @@ class EnvItemCell extends StatelessWidget { maxLines: 1, style: TextStyle( overflow: TextOverflow.ellipsis, - color: ref.watch(themeProvider).themeColor.descColor(), + color: ref + .watch(themeProvider) + .themeColor + .descColor(), fontSize: 12, ), ), @@ -375,7 +407,8 @@ class EnvItemCell extends StatelessWidget { maxLines: 1, style: TextStyle( overflow: TextOverflow.ellipsis, - color: ref.watch(themeProvider).themeColor.descColor(), + color: + ref.watch(themeProvider).themeColor.descColor(), fontSize: 12, ), ), diff --git a/lib/module/env/env_viewmodel.dart b/lib/module/env/env_viewmodel.dart index 50ab7d9..05cfbc9 100644 --- a/lib/module/env/env_viewmodel.dart +++ b/lib/module/env/env_viewmodel.dart @@ -15,7 +15,6 @@ class EnvViewModel extends BaseViewModel { List disabledList = []; List enabledList = []; - Future loadData([isLoading = true]) async { if (isLoading && list.isEmpty) { loading(notify: true); @@ -23,12 +22,12 @@ 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()); + disabledList + .addAll(list.where((element) => element.status == 1).toList()); enabledList.clear(); enabledList.addAll(list.where((element) => element.status == 0).toList()); success(); diff --git a/lib/module/login/login_page.dart b/lib/module/login/login_page.dart index 37042b3..5afdb7c 100644 --- a/lib/module/login/login_page.dart +++ b/lib/module/login/login_page.dart @@ -44,7 +44,8 @@ class _LoginPageState extends ConsumerState { if (!widget.doNotLoadLocalData) { _hostController.text = getIt().host ?? ""; 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 { @@ -54,7 +55,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 { @@ -76,7 +78,9 @@ class _LoginPageState extends ConsumerState { Widget build(BuildContext context) { return Scaffold( body: AnnotatedRegion( - value: ref.watch(themeProvider).darkMode == true ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark, + value: ref.watch(themeProvider).darkMode == true + ? SystemUiOverlayStyle.light + : SystemUiOverlayStyle.dark, child: ColoredBox( color: ref.watch(themeProvider).themeColor.settingBgColor(), child: SingleChildScrollView( @@ -105,7 +109,10 @@ class _LoginPageState extends ConsumerState { style: TextStyle( fontSize: 26, fontWeight: FontWeight.bold, - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), ), ), ), @@ -115,7 +122,9 @@ class _LoginPageState extends ConsumerState { if (debugBtnIsShow()) { dismissDebugBtn(); } else { - showDebugBtn(context, btnColor: ref.watch(themeProvider).primaryColor); + showDebugBtn(context, + btnColor: + ref.watch(themeProvider).primaryColor); } WidgetsBinding.instance.endOfFrame; }, @@ -158,7 +167,10 @@ class _LoginPageState extends ConsumerState { hintText: "http://1.1.1.1:5700", hintStyle: TextStyle( fontSize: 16, - color: ref.watch(themeProvider).themeColor.descColor(), + color: ref + .watch(themeProvider) + .themeColor + .descColor(), ), ), autofocus: false, @@ -216,7 +228,10 @@ class _LoginPageState extends ConsumerState { hintText: "请输入账户", hintStyle: TextStyle( fontSize: 16, - color: ref.watch(themeProvider).themeColor.descColor(), + color: ref + .watch(themeProvider) + .themeColor + .descColor(), ), ), autofocus: false, @@ -260,7 +275,10 @@ class _LoginPageState extends ConsumerState { hintText: "请输入密码", hintStyle: TextStyle( fontSize: 16, - color: ref.watch(themeProvider).themeColor.descColor(), + color: ref + .watch(themeProvider) + .themeColor + .descColor(), ), ), autofocus: false, @@ -310,7 +328,10 @@ class _LoginPageState extends ConsumerState { hintText: "请输入client_id", hintStyle: TextStyle( fontSize: 16, - color: ref.watch(themeProvider).themeColor.descColor(), + color: ref + .watch(themeProvider) + .themeColor + .descColor(), ), ), autofocus: false, @@ -354,7 +375,10 @@ class _LoginPageState extends ConsumerState { hintText: "请输入client_secret", hintStyle: TextStyle( fontSize: 16, - color: ref.watch(themeProvider).themeColor.descColor(), + color: ref + .watch(themeProvider) + .themeColor + .descColor(), ), ), autofocus: false, @@ -399,7 +423,8 @@ class _LoginPageState extends ConsumerState { GestureDetector( onTap: () { cardKey.currentState?.toggleCard(); - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance + .addPostFrameCallback((timeStamp) { setState(() {}); }); }, @@ -421,7 +446,8 @@ class _LoginPageState extends ConsumerState { height: 30, ), Shake( - preferences: const AnimationPreferences(autoPlay: AnimationPlayStates.None), + preferences: const AnimationPreferences( + autoPlay: AnimationPlayStates.None), key: loginKey, child: Center( child: Container( @@ -469,9 +495,11 @@ class _LoginPageState extends ConsumerState { Http.pushedLoginPage = false; Utils.hideKeyBoard(context); if (loginByUserName()) { - login(_userNameController.text, _passwordController.text); + login(_userNameController.text, + _passwordController.text); } else { - login(_cIdController.text, _cSecretController.text); + login(_cIdController.text, + _cSecretController.text); } }, ); @@ -498,7 +526,8 @@ class _LoginPageState extends ConsumerState { onSelected: (UserInfoBean result) { selected(result); }, - itemBuilder: (BuildContext context) => >[ + itemBuilder: (BuildContext context) => + >[ ...getIt() .historyAccounts .map( @@ -554,7 +583,8 @@ class _LoginPageState extends ConsumerState { isLoading = true; setState(() {}); - helper = LoginHelper(useSecretLogin, _hostController.text, userName, password, rememberPassword); + helper = LoginHelper(useSecretLogin, _hostController.text, userName, + password, rememberPassword); var response = await helper!.login(); dealLoginResponse(response); } @@ -581,9 +611,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; } } diff --git a/lib/module/login/user_bean.dart b/lib/module/login/user_bean.dart index 4ace31f..e3d2a83 100644 --- a/lib/module/login/user_bean.dart +++ b/lib/module/login/user_bean.dart @@ -19,6 +19,7 @@ class UserBean { data['twoFactorActivated'] = this.twoFactorActivated; return data; } + static UserBean jsonConversion(Map json) { return UserBean.fromJson(json); } diff --git a/lib/module/others/about_page.dart b/lib/module/others/about_page.dart index 78d852e..a6d4a51 100644 --- a/lib/module/others/about_page.dart +++ b/lib/module/others/about_page.dart @@ -23,7 +23,6 @@ class _AboutPageState extends ConsumerState { void initState() { super.initState(); getInfo(); - } @override @@ -88,7 +87,8 @@ class _AboutPageState extends ConsumerState { const Spacer(), GestureDetector( onTap: () { - _launchURL("https://github.com/qinglong-app/qinglong_app/releases"); + _launchURL( + "https://github.com/qinglong-app/qinglong_app/releases"); }, child: Text( "版本更新", diff --git a/lib/module/others/dependencies/dependency_page.dart b/lib/module/others/dependencies/dependency_page.dart index 150c2f8..e2bf41e 100644 --- a/lib/module/others/dependencies/dependency_page.dart +++ b/lib/module/others/dependencies/dependency_page.dart @@ -21,7 +21,8 @@ class DependencyPage extends StatefulWidget { _DependcyPageState createState() => _DependcyPageState(); } -class _DependcyPageState extends State with TickerProviderStateMixin { +class _DependcyPageState extends State + with TickerProviderStateMixin { List types = []; TabController? _tabController; @@ -125,7 +126,9 @@ class _DependcyPageState extends State with TickerProviderStateM itemCount: list.length, ), onRefresh: () { - return model.loadData(types[_tabController!.index].name.toLowerCase(), false); + return model.loadData( + types[_tabController!.index].name.toLowerCase(), + false); }, ); }, @@ -222,7 +225,10 @@ class DependencyCell extends ConsumerWidget { maxLines: 1, style: TextStyle( overflow: TextOverflow.ellipsis, - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 18, ), ), @@ -255,11 +261,16 @@ class DependencyCell extends ConsumerWidget { child: Material( color: Colors.transparent, child: Text( - (bean.created == null || bean.created == 0) ? "-" : Utils.formatMessageTime(bean.created!), + (bean.created == null || bean.created == 0) + ? "-" + : Utils.formatMessageTime(bean.created!), maxLines: 1, style: TextStyle( overflow: TextOverflow.ellipsis, - color: ref.watch(themeProvider).themeColor.descColor(), + color: ref + .watch(themeProvider) + .themeColor + .descColor(), fontSize: 12, ), ), @@ -357,7 +368,9 @@ class DependencyCell extends ConsumerWidget { ), onPressed: () { Navigator.of(context).pop(); - ref.read(dependencyProvider).del(type.name.toLowerCase(), sId ?? ""); + ref + .read(dependencyProvider) + .del(type.name.toLowerCase(), sId ?? ""); }, ), ], diff --git a/lib/module/others/dependencies/dependency_viewmodel.dart b/lib/module/others/dependencies/dependency_viewmodel.dart index e96e187..aa70dc2 100644 --- a/lib/module/others/dependencies/dependency_viewmodel.dart +++ b/lib/module/others/dependencies/dependency_viewmodel.dart @@ -15,7 +15,10 @@ class DependencyViewModel extends BaseViewModel { List linuxList = []; Future loadData(String type, [bool showLoading = true]) async { - if (showLoading && ((type == "nodejs" && nodeJsList.isEmpty) || (type == "python3" && python3List.isEmpty) || (type == "linux" && linuxList.isEmpty))) { + if (showLoading && + ((type == "nodejs" && nodeJsList.isEmpty) || + (type == "python3" && python3List.isEmpty) || + (type == "linux" && linuxList.isEmpty))) { loading(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 bc4afc9..ab51a05 100644 --- a/lib/module/others/login_log/login_log_page.dart +++ b/lib/module/others/login_log/login_log_page.dart @@ -37,99 +37,98 @@ class _LoginLogPageState extends ConsumerState ), body: list.isEmpty ? const Center( - child: CupertinoActivityIndicator(), - ) + child: CupertinoActivityIndicator(), + ) : ListView.separated( - itemBuilder: (context, index) { - LoginLogBean item = list[index]; + itemBuilder: (context, index) { + LoginLogBean item = list[index]; - return Row( - children: [ - const SizedBox( - width: 15, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox( - height: 10, - ), - 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, + return Row( + children: [ + const SizedBox( + width: 15, ), - ), - 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, - ); - }, - ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 10, + ), + 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 729360b..17153b8 100644 --- a/lib/module/others/other_page.dart +++ b/lib/module/others/other_page.dart @@ -53,7 +53,10 @@ class _OtherPageState extends ConsumerState { Text( "脚本管理", style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 16, ), ), @@ -86,7 +89,10 @@ class _OtherPageState extends ConsumerState { Text( "依赖管理", style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 16, ), ), @@ -121,7 +127,10 @@ class _OtherPageState extends ConsumerState { Text( "任务日志", style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 16, ), ), @@ -161,7 +170,10 @@ class _OtherPageState extends ConsumerState { Text( "登录日志", style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 16, ), ), @@ -177,7 +189,6 @@ class _OtherPageState extends ConsumerState { const Divider( indent: 15, ), - GestureDetector( onTap: () { if (getIt().useSecretLogined) { @@ -203,7 +214,10 @@ class _OtherPageState extends ConsumerState { Text( "修改密码", style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 16, ), ), @@ -240,7 +254,8 @@ class _OtherPageState extends ConsumerState { Text( "夜间模式", style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: + ref.watch(themeProvider).themeColor.titleColor(), fontSize: 16, ), ), @@ -270,7 +285,8 @@ class _OtherPageState extends ConsumerState { Text( "查看代码是否显示行号", style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: + ref.watch(themeProvider).themeColor.titleColor(), fontSize: 16, ), ), @@ -309,7 +325,10 @@ class _OtherPageState extends ConsumerState { Text( "主题设置", style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 16, ), ), @@ -344,7 +363,10 @@ class _OtherPageState extends ConsumerState { Text( "切换账号", style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 16, ), ), @@ -381,7 +403,10 @@ class _OtherPageState extends ConsumerState { Text( "关于", style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 16, ), ), @@ -440,7 +465,8 @@ class _OtherPageState extends ConsumerState { ), onPressed: () { getIt().updateToken(""); - Navigator.of(context).pushReplacementNamed(Routes.routeLogin); + Navigator.of(context) + .pushReplacementNamed(Routes.routeLogin); }, ), ], diff --git a/lib/module/others/scripts/script_code_detail_page.dart b/lib/module/others/scripts/script_code_detail_page.dart new file mode 100644 index 0000000..9dd77c8 --- /dev/null +++ b/lib/module/others/scripts/script_code_detail_page.dart @@ -0,0 +1,154 @@ +import 'package:code_text_field/code_text_field.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:highlight/languages/javascript.dart'; +import 'package:highlight/languages/json.dart'; +import 'package:highlight/languages/powershell.dart'; +import 'package:highlight/languages/python.dart'; +import 'package:highlight/languages/vbscript-html.dart'; +import 'package:highlight/languages/yaml.dart'; +import 'package:qinglong_app/base/ql_app_bar.dart'; +import 'package:qinglong_app/base/sp_const.dart'; +import 'package:qinglong_app/base/theme.dart'; +import 'package:qinglong_app/utils/sp_utils.dart'; + +/// @author NewTab +class ScriptCodeDetailPage extends ConsumerStatefulWidget { + final String title; + final String content; + + const ScriptCodeDetailPage({ + Key? key, + required this.title, + required this.content, + }) : super(key: key); + + @override + ScriptCodeDetailPageState createState() => ScriptCodeDetailPageState(); +} + +class ScriptCodeDetailPageState extends ConsumerState { + CodeController? _codeController; + GlobalKey codeFieldKey = GlobalKey(); + + bool buttonshow = false; + + void scrollToTop() { + codeFieldKey.currentState?.getCodeScroll()?.animateTo(0, + duration: const Duration(milliseconds: 200), curve: Curves.linear); + } + + void floatingButtonVisibility() { + double y = codeFieldKey.currentState?.getCodeScroll()?.offset ?? 0; + if (y > MediaQuery.of(context).size.height / 2) { + if (buttonshow == true) return; + setState(() { + buttonshow = true; + }); + } else { + if (buttonshow == false) return; + setState(() { + buttonshow = false; + }); + } + } + + String suffix = "\n\n\n"; + + @override + void dispose() { + _codeController?.dispose(); + _codeController = null; + super.dispose(); + } + + getLanguageType(String title) { + if (title.endsWith(".js")) { + return javascript; + } + + if (title.endsWith(".sh")) { + return powershell; + } + + if (title.endsWith(".py")) { + return python; + } + if (title.endsWith(".json")) { + return json; + } + if (title.endsWith(".yaml")) { + return yaml; + } + return vbscriptHtml; + } + + late String content; + + @override + void initState() { + content = widget.content; + super.initState(); + } + + @override + Widget build(BuildContext context) { + _codeController ??= CodeController( + text: (content) + suffix, + language: getLanguageType(widget.title), + onChange: (value) { + content = value + suffix; + }, + theme: ref.watch(themeProvider).themeColor.codeEditorTheme(), + stringMap: { + "export": const TextStyle( + fontWeight: FontWeight.normal, color: Color(0xff6B2375)), + }, + ); + return Scaffold( + floatingActionButton: Visibility( + visible: buttonshow, + child: FloatingActionButton( + mini: true, + onPressed: () { + scrollToTop(); + }, + elevation: 2, + backgroundColor: Colors.white, + child: const Icon(CupertinoIcons.up_arrow), + ), + ), + appBar: QlAppBar( + canBack: true, + backCall: () { + Navigator.of(context).pop(); + }, + title: widget.title, + ), + body: SafeArea( + top: false, + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: SpUtil.getBool(spShowLine, defValue: false) ? 0 : 10, + ), + child: CodeField( + key: codeFieldKey, + controller: _codeController!, + expands: true, + readOnly: true, + wrap: SpUtil.getBool(spShowLine, defValue: false) ? false : true, + hideColumn: !SpUtil.getBool(spShowLine, defValue: false), + lineNumberStyle: LineNumberStyle( + textStyle: TextStyle( + color: ref.watch(themeProvider).themeColor.descColor(), + fontSize: 12, + ), + ), + background: Colors.white, + ), + ), + ), + ); + } +} diff --git a/lib/module/others/scripts/script_detail_page.dart b/lib/module/others/scripts/script_detail_page.dart index 57e58cf..bbe2cfb 100644 --- a/lib/module/others/scripts/script_detail_page.dart +++ b/lib/module/others/scripts/script_detail_page.dart @@ -33,7 +33,8 @@ class ScriptDetailPage extends ConsumerStatefulWidget { _ScriptDetailPageState createState() => _ScriptDetailPageState(); } -class _ScriptDetailPageState extends ConsumerState with LazyLoadState { +class _ScriptDetailPageState extends ConsumerState + with LazyLoadState { String? content; CodeController? _codeController; GlobalKey codeFieldKey = GlobalKey(); @@ -42,7 +43,8 @@ class _ScriptDetailPageState extends ConsumerState with LazyLo bool buttonshow = false; void scrollToTop() { - codeFieldKey.currentState?.getCodeScroll()?.animateTo(0, duration: const Duration(milliseconds: 200), curve: Curves.linear); + codeFieldKey.currentState?.getCodeScroll()?.animateTo(0, + duration: const Duration(milliseconds: 200), curve: Curves.linear); } void floatingButtonVisibility() { @@ -164,7 +166,8 @@ class _ScriptDetailPageState extends ConsumerState with LazyLo ), onPressed: () async { Navigator.of(context).pop(); - HttpResponse result = await Api.delScript(widget.title, widget.path ?? ""); + HttpResponse result = + await Api.delScript(widget.title, widget.path ?? ""); if (result.success) { "删除成功".toast(); Navigator.of(context).pop(true); @@ -209,7 +212,8 @@ class _ScriptDetailPageState extends ConsumerState with LazyLo }, theme: ref.watch(themeProvider).themeColor.codeEditorTheme(), stringMap: { - "export": const TextStyle(fontWeight: FontWeight.normal, color: Color(0xff6B2375)), + "export": const TextStyle( + fontWeight: FontWeight.normal, color: Color(0xff6B2375)), }, ); } @@ -296,31 +300,34 @@ class _ScriptDetailPageState extends ConsumerState with LazyLo ), body: content == null ? const Center( - child: CupertinoActivityIndicator(), - ) + child: CupertinoActivityIndicator(), + ) : SafeArea( - top: false, - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: SpUtil.getBool(spShowLine, defValue: false) ? 0 : 10, - ), - child: CodeField( - key: codeFieldKey, - controller: _codeController!, - expands: true, - readOnly: true, - wrap: SpUtil.getBool(spShowLine, defValue: false) ? false : true, - hideColumn: !SpUtil.getBool(spShowLine, defValue: false), - lineNumberStyle: LineNumberStyle( - textStyle: TextStyle( - color: ref.watch(themeProvider).themeColor.descColor(), - fontSize: 12, + top: false, + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: + SpUtil.getBool(spShowLine, defValue: false) ? 0 : 10, + ), + child: CodeField( + key: codeFieldKey, + controller: _codeController!, + expands: true, + readOnly: true, + wrap: SpUtil.getBool(spShowLine, defValue: false) + ? false + : true, + hideColumn: !SpUtil.getBool(spShowLine, defValue: false), + lineNumberStyle: LineNumberStyle( + textStyle: TextStyle( + color: ref.watch(themeProvider).themeColor.descColor(), + fontSize: 12, + ), + ), + background: Colors.white, + ), ), ), - background: Colors.white, - ), - ), - ), ); } @@ -337,8 +344,10 @@ class _ScriptDetailPageState extends ConsumerState with LazyLo const Duration( seconds: 1, ), - () { - codeFieldKey.currentState?.getCodeScroll()?.addListener(floatingButtonVisibility); + () { + codeFieldKey.currentState + ?.getCodeScroll() + ?.addListener(floatingButtonVisibility); }, ); } else { diff --git a/lib/module/others/scripts/script_edit_page.dart b/lib/module/others/scripts/script_edit_page.dart index 5986356..a5b918f 100644 --- a/lib/module/others/scripts/script_edit_page.dart +++ b/lib/module/others/scripts/script_edit_page.dart @@ -21,7 +21,8 @@ class ScriptEditPage extends ConsumerStatefulWidget { final String title; final String path; - const ScriptEditPage(this.title, this.path, this.content, {Key? key}) : super(key: key); + const ScriptEditPage(this.title, this.path, this.content, {Key? key}) + : super(key: key); @override _ScriptEditPageState createState() => _ScriptEditPageState(); @@ -81,7 +82,8 @@ class _ScriptEditPageState extends ConsumerState { }, theme: ref.watch(themeProvider).themeColor.codeEditorTheme(), stringMap: { - "export": const TextStyle(fontWeight: FontWeight.normal, color: Color(0xff6B2375)), + "export": const TextStyle( + fontWeight: FontWeight.normal, color: Color(0xff6B2375)), }, ); return Scaffold( @@ -132,7 +134,8 @@ class _ScriptEditPageState extends ConsumerState { actions: [ InkWell( onTap: () async { - HttpResponse response = await Api.updateScript(widget.title, widget.path, result); + HttpResponse response = + await Api.updateScript(widget.title, widget.path, result); if (response.success) { "提交成功".toast(); Navigator.of(context).pop(true); diff --git a/lib/module/others/scripts/script_page.dart b/lib/module/others/scripts/script_page.dart index 28291c9..f435901 100644 --- a/lib/module/others/scripts/script_page.dart +++ b/lib/module/others/scripts/script_page.dart @@ -11,6 +11,8 @@ 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'; +import 'script_upload_page.dart'; + /// @author NewTab class ScriptPage extends ConsumerStatefulWidget { const ScriptPage({Key? key}) : super(key: key); @@ -19,7 +21,8 @@ class ScriptPage extends ConsumerStatefulWidget { _ScriptPageState createState() => _ScriptPageState(); } -class _ScriptPageState extends ConsumerState with LazyLoadState { +class _ScriptPageState extends ConsumerState + with LazyLoadState { List list = []; final TextEditingController _searchController = TextEditingController(); @@ -75,7 +78,8 @@ class _ScriptPageState extends ConsumerState with LazyLoadState with LazyLoadState ListTile( - onTap: () { - Navigator.of(context).pushNamed( - Routes.routeScriptDetail, - arguments: { - "title": e.title, - "path": e.parent, + color: + ref.watch(themeProvider).themeColor.settingBgColor(), + child: + (item.children != null && item.children!.isNotEmpty) + ? ExpansionTile( + title: Text( + item.title ?? "", + style: TextStyle( + color: (item.disabled ?? false) + ? ref + .watch(themeProvider) + .themeColor + .descColor() + : ref + .watch(themeProvider) + .themeColor + .titleColor(), + fontSize: 16, + ), + ), + children: item.children! + .where((element) { + if (_searchController.text.isEmpty) { + return true; + } + return (element.title?.contains( + _searchController.text) ?? + false) || + (element.value?.contains( + _searchController.text) ?? + false); + }) + .map((e) => ListTile( + onTap: () { + Navigator.of(context).pushNamed( + Routes.routeScriptDetail, + arguments: { + "title": e.title, + "path": e.parent, + }, + ).then((value) { + if (value != null && + value == true) { + loadData(); + } + }); }, - ).then((value) { - if (value != null && value == true) { - loadData(); - } - }); - }, - title: Text( - e.title ?? "", - style: TextStyle( - color: (item.disabled ?? false) - ? ref.watch(themeProvider).themeColor.descColor() - : ref.watch(themeProvider).themeColor.titleColor(), - fontSize: 14, - ), - ), - )) - .toList(), - ) - : ListTile( - onTap: () { - Navigator.of(context).pushNamed( - Routes.routeScriptDetail, - arguments: { - "title": item.title, - "path": "", + title: Text( + e.title ?? "", + style: TextStyle( + color: (item.disabled ?? false) + ? ref + .watch(themeProvider) + .themeColor + .descColor() + : ref + .watch(themeProvider) + .themeColor + .titleColor(), + fontSize: 14, + ), + ), + )) + .toList(), + ) + : ListTile( + onTap: () { + Navigator.of(context).pushNamed( + Routes.routeScriptDetail, + arguments: { + "title": item.title, + "path": "", + }, + ).then( + (value) { + if (value != null && value == true) { + loadData(); + } + }, + ); }, - ).then( - (value) { - if (value != null && value == true) { - loadData(); - } - }, - ); - }, - title: Text( - item.title ?? "", - style: TextStyle( - color: (item.disabled ?? false) - ? ref.watch(themeProvider).themeColor.descColor() - : ref.watch(themeProvider).themeColor.titleColor(), - fontSize: 16, + title: Text( + item.title ?? "", + style: TextStyle( + color: (item.disabled ?? false) + ? ref + .watch(themeProvider) + .themeColor + .descColor() + : ref + .watch(themeProvider) + .themeColor + .titleColor(), + fontSize: 16, + ), + ), ), - ), - ), ); } else { return const SizedBox.shrink(); @@ -209,144 +241,12 @@ class _ScriptPageState extends ConsumerState with LazyLoadState CupertinoAlertDialog( - title: const Text("新增脚本"), - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox( - height: 10, - ), - const Text( - "脚本名称:", - style: TextStyle( - fontSize: 14, - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 10, - ), - child: Material( - color: Colors.transparent, - child: TextField( - controller: _nameController, - decoration: const InputDecoration( - isDense: true, - contentPadding: EdgeInsets.all(4), - hintText: "请输入脚本名称", - hintStyle: TextStyle( - fontSize: 14, - ), - ), - autofocus: false, - ), - ), - ), - const SizedBox( - height: 10, - ), - const Material( - color: Colors.transparent, - child: Text( - "脚本所属文件夹:", - style: TextStyle( - fontSize: 14, - ), - ), - ), - const SizedBox( - height: 10, - ), - Material( - color: Colors.transparent, - child: DropdownButtonFormField( - items: list - .where((element) => element.children?.isNotEmpty ?? false) - .map((e) => DropdownMenuItem( - value: e.value, - child: SizedBox( - width: MediaQuery.of(context).size.width / 2, - child: Text( - e.value ?? "", - maxLines: 2, - ), - ), - )) - .toList() - ..insert( - 0, - DropdownMenuItem( - value: "", - child: SizedBox( - width: MediaQuery.of(context).size.width / 2, - child: const Text( - "根目录", - maxLines: 2, - ), - ), - )), - value: scriptPath, - onChanged: (value) { - scriptPath = value ?? ""; - }, - ), - ), - ], - ), - 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 { - "提交中...".toast(); - HttpResponse response = await Api.addScript( - _nameController.text, - scriptPath, - "## created by 青龙客户端 ${DateTime.now()}\n\n", - ); - if (response.success) { - "提交成功".toast(); - Navigator.of(context).pop(); - Navigator.of(context).pushNamed( - Routes.routeScriptUpdate, - arguments: { - "title": _nameController.text, - "path": scriptPath, - "content": "## created by 青龙客户端 ${DateTime.now()}\n\n", - }, - ).then((value) { - if (value != null && value == true) { - _nameController.text = ""; - loadData(); - } - }); - } else { - (response.message ?? "").toast(); - } - }, - ), - ], - ), - ); + List paths = list + .where((element) => element.children?.isNotEmpty ?? false) + .map((e) => e.title) + .toList(); + + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => ScriptUploadPage(paths: paths))); } } diff --git a/lib/module/others/scripts/script_upload_page.dart b/lib/module/others/scripts/script_upload_page.dart new file mode 100644 index 0000000..10c1896 --- /dev/null +++ b/lib/module/others/scripts/script_upload_page.dart @@ -0,0 +1,425 @@ +import 'dart:io'; +import 'dart:math'; + +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.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:path/path.dart'; +import 'package:qinglong_app/module/others/scripts/script_code_detail_page.dart'; +import 'package:qinglong_app/module/task/task_bean.dart'; +import 'package:qinglong_app/utils/extension.dart'; + +/// @author NewTab + +class ScriptUploadPage extends ConsumerStatefulWidget { + final List paths; + + const ScriptUploadPage({ + Key? key, + required this.paths, + }) : super(key: key); + + @override + ConsumerState createState() => ScriptUploadPageState(); +} + +class ScriptUploadPageState extends ConsumerState { + List list = []; + + final TextEditingController _nameController = TextEditingController(); + String scriptPath = ""; + File? file; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: QlAppBar( + title: "新增脚本", + actions: [ + InkWell( + onTap: () { + submit(context); + }, + child: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 15, + ), + child: Center( + child: Text( + "提交", + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ), + ), + ), + ) + ], + ), + body: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 30, + ), + const TitleWidget( + "脚本名称", + ), + TextField( + controller: _nameController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.fromLTRB(0, 5, 0, 5), + hintText: "请输入脚本名称", + hintStyle: TextStyle( + fontSize: 14, + color: ref.watch(themeProvider).themeColor.descColor(), + ), + ), + autofocus: false, + ), + const SizedBox( + height: 30, + ), + const TitleWidget( + "脚本目录", + ), + const SizedBox( + height: 10, + ), + DropdownButtonFormField( + items: widget.paths + .map((e) => DropdownMenuItem( + value: e, + child: SizedBox( + width: MediaQuery.of(context).size.width / 2, + child: Text( + e ?? "", + maxLines: 2, + ), + ), + )) + .toList() + ..insert( + 0, + DropdownMenuItem( + value: "", + child: SizedBox( + width: MediaQuery.of(context).size.width / 2, + child: const Text( + "根目录", + maxLines: 2, + ), + ), + ), + ), + style: TextStyle( + fontSize: 14, + color: ref.watch(themeProvider).themeColor.titleColor(), + ), + decoration: const InputDecoration( + isDense: true, + contentPadding: EdgeInsets.symmetric( + vertical: 15, + ), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Color(0xfff5f5f5), + ), + ), + border: UnderlineInputBorder( + borderSide: BorderSide( + color: Color(0xfff5f5f5), + ), + ), + ), + value: scriptPath, + onChanged: (value) { + scriptPath = value ?? ""; + }, + ), + const SizedBox( + height: 30, + ), + const TitleWidget( + "上传脚本", + ), + const SizedBox( + height: 10, + ), + Container( + height: 80, + alignment: Alignment.centerLeft, + child: file == null ? addWidget() : addedWidget(context), + ), + ], + ), + ), + const SizedBox( + height: 50, + ), + ], + ), + ), + ); + } + + Widget addWidget() { + return GestureDetector( + onTap: () async { + FilePickerResult? result = await FilePicker.platform.pickFiles(); + if (result != null && + result.files.isNotEmpty && + result.files.single.path != null) { + file = File(result.files.single.path!); + + if (file == null) return; + if (file!.lengthSync() > 5242880) { + file = null; + "最大支持上传5M的文件".toast(); + return; + } + + _nameController.text = getFileName(); + setState(() {}); + } + }, + child: Container( + margin: const EdgeInsets.only( + top: 10, + ), + width: 70, + height: 70, + decoration: BoxDecoration( + color: const Color(0xfff3f5f7), + borderRadius: BorderRadius.circular(5), + ), + child: Center( + child: Image.asset( + "assets/images/icon_add_file.png", + width: 50, + fit: BoxFit.cover, + ), + ), + ), + ); + } + + Widget addedWidget(BuildContext context) { + return GestureDetector( + onTap: () async { + try { + String content = await file!.readAsString(); + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => ScriptCodeDetailPage( + title: getFileName(), + content: content, + ), + ), + ); + } catch (e) { + e.toString().toast(); + } + }, + behavior: HitTestBehavior.opaque, + child: Container( + height: 80, + padding: const EdgeInsets.symmetric( + vertical: 10, + ), + child: Row( + children: [ + Image.asset( + getIconBySuffix(), + width: 50, + fit: BoxFit.cover, + ), + const SizedBox( + width: 15, + ), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + getFileName(), + style: TextStyle( + color: ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 16, + ), + ), + const SizedBox( + height: 5, + ), + Text( + getFileSize(file!.path, 1), + style: TextStyle( + color: ref.watch(themeProvider).themeColor.descColor(), + fontSize: 12, + ), + ), + ], + ), + ), + const Spacer(), + GestureDetector( + onTap: () { + file = null; + _nameController.text = ""; + setState(() {}); + }, + child: Icon( + CupertinoIcons.clear, + size: 20, + color: ref.watch(themeProvider).themeColor.descColor(), + ), + ), + ], + ), + ), + ); + } + + String getFileSize(String filepath, int decimals) { + var file = File(filepath); + int bytes = file.lengthSync(); + if (bytes <= 0) return "0 B"; + const suffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + var i = (log(bytes) / log(1024)).floor(); + return '${(bytes / pow(1024, i)).toStringAsFixed(decimals)} ${suffixes[i]}'; + } + + String getFileName() { + return basename(file!.path); + } + + String getIconBySuffix() { + String end = file!.path; + + if (end.endsWith(".py")) { + return "assets/images/py.png"; + } + if (end.endsWith(".js")) { + return "assets/images/js.png"; + } + if (end.endsWith(".ts")) { + return "assets/images/ts.png"; + } + if (end.endsWith(".json")) { + return "assets/images/json.png"; + } + if (end.endsWith(".sh")) { + return "assets/images/shell.png"; + } + return "assets/images/other.png"; + } + + void submit(BuildContext context) async { + try { + if (_nameController.text.isEmpty) { + "请输入文件名称".toast(); + return; + } + + if (file == null) { + Navigator.of(context).pushNamed( + Routes.routeScriptAdd, + arguments: { + "title": _nameController.text, + "path": scriptPath, + }, + ).then((value) { + if (value != null && value == true) { + Navigator.of(context).pop(true); + } + }); + } else { + String content = await file!.readAsString(); + HttpResponse response = await Api.addScript( + _nameController.text, + scriptPath, + content, + ); + if (response.success) { + "提交成功".toast(); + + String command = + "task $scriptPath${(scriptPath.isNotEmpty) ? separator : ""}${getFileName()} "; + + String? cron = getCronString(content, getFileName()); + Navigator.of(context).popAndPushNamed( + Routes.routeAddTask, + arguments: TaskBean( + name: _nameController.text, + command: command, + schedule: cron, + ), + ); + } else { + (response.message ?? "").toast(); + } + } + } catch (e) { + e.toString().toast(); + } + } + + static String? getCronString(String pre, String fileName) { + String reg = + "([\\d\\*]*[\\*-\\/,\\d]*[\\d\\*] ){4,5}[\\d\\*]*[\\*-\\/,\\d]*[\\d\\*]( |,|\").*$fileName"; + RegExp regExp = RegExp(reg); + RegExpMatch? result = regExp.firstMatch(pre); + return result?[0]?.replaceAll(fileName, "").trim(); + } +} + +class TitleWidget extends ConsumerWidget { + final String title; + final bool required; + + const TitleWidget( + this.title, { + Key? key, + this.required = false, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + return RichText( + text: TextSpan( + text: !required ? "" : "* ", + style: const TextStyle( + color: Color(0xFFF02D2D), + ), + children: [ + TextSpan( + text: title, + style: TextStyle( + fontSize: 16, + color: ref.watch(themeProvider).themeColor.titleColor(), + ), + ), + ], + ), + ); + } +} diff --git a/lib/module/others/task_log/task_log_detail_page.dart b/lib/module/others/task_log/task_log_detail_page.dart index dfcd3b6..93948e9 100644 --- a/lib/module/others/task_log/task_log_detail_page.dart +++ b/lib/module/others/task_log/task_log_detail_page.dart @@ -24,7 +24,8 @@ class TaskLogDetailPage extends ConsumerStatefulWidget { _TaskLogDetailPageState createState() => _TaskLogDetailPageState(); } -class _TaskLogDetailPageState extends ConsumerState with LazyLoadState { +class _TaskLogDetailPageState extends ConsumerState + with LazyLoadState { String? content; @override @@ -40,15 +41,15 @@ class _TaskLogDetailPageState extends ConsumerState with Lazy body: content == null ? const Center(child: CupertinoActivityIndicator()) : Padding( - padding: const EdgeInsets.symmetric( - horizontal: 15, - ), - child: SelectableText( - (content == null || content!.isEmpty) ? "暂无数据" : content!, - selectionHeightStyle: BoxHeightStyle.max, - selectionWidthStyle: BoxWidthStyle.max, - ), - ), + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: SelectableText( + (content == null || content!.isEmpty) ? "暂无数据" : content!, + selectionHeightStyle: BoxHeightStyle.max, + selectionWidthStyle: BoxWidthStyle.max, + ), + ), ); } diff --git a/lib/module/others/task_log/task_log_page.dart b/lib/module/others/task_log/task_log_page.dart index 2541940..d873c85 100644 --- a/lib/module/others/task_log/task_log_page.dart +++ b/lib/module/others/task_log/task_log_page.dart @@ -19,7 +19,8 @@ class TaskLogPage extends ConsumerStatefulWidget { _TaskLogPageState createState() => _TaskLogPageState(); } -class _TaskLogPageState extends ConsumerState with LazyLoadState { +class _TaskLogPageState extends ConsumerState + with LazyLoadState { List list = []; final TextEditingController _searchController = TextEditingController(); @@ -63,7 +64,8 @@ class _TaskLogPageState extends ConsumerState with LazyLoadState with LazyLoadState with LazyLoadState ListTile( onTap: () { - Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: { - "path": item.name, - "title": e, - }); + Navigator.of(context).pushNamed( + Routes.routeTaskLogDetail, + arguments: { + "path": item.name, + "title": e, + }); }, title: Text( e, style: TextStyle( - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 14, ), ), @@ -98,15 +108,20 @@ class _TaskLogPageState extends ConsumerState with LazyLoadState ListTile( onTap: () { - Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: { - "path": item.name, - "title": e.title, - }); + 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(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 14, ), ), @@ -119,15 +134,20 @@ class _TaskLogPageState extends ConsumerState with LazyLoadState { ), child: Column( mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -144,7 +145,8 @@ class _ThemePageState extends ConsumerState { child: CircularProgressIndicator( strokeWidth: 2, - color: _primaryColor, + color: + _primaryColor, ), ), SizedBox( @@ -158,8 +160,8 @@ class _ThemePageState extends ConsumerState { child: Text( "示例名称", maxLines: 1, - overflow: - TextOverflow.ellipsis, + overflow: TextOverflow + .ellipsis, style: TextStyle( overflow: TextOverflow .ellipsis, @@ -182,7 +184,8 @@ class _ThemePageState extends ConsumerState { "上午10:00", maxLines: 1, style: TextStyle( - overflow: TextOverflow.ellipsis, + overflow: + TextOverflow.ellipsis, color: ref .watch(themeProvider) .themeColor @@ -216,7 +219,8 @@ class _ThemePageState extends ConsumerState { "10 1-12/2 * * *", maxLines: 1, style: TextStyle( - overflow: TextOverflow.ellipsis, + overflow: + TextOverflow.ellipsis, color: ref .watch(themeProvider) .themeColor diff --git a/lib/module/task/add_task_page.dart b/lib/module/task/add_task_page.dart index 401b64b..4aed39b 100644 --- a/lib/module/task/add_task_page.dart +++ b/lib/module/task/add_task_page.dart @@ -207,8 +207,11 @@ class _AddTaskPageState extends ConsumerState { taskBean.command = _commandController.text; taskBean.schedule = _cronController.text; HttpResponse response = await Api.addTask( - _nameController.text, _commandController.text, _cronController.text, - id: taskBean.id,); + _nameController.text, + _commandController.text, + _cronController.text, + id: taskBean.id, + ); if (response.success) { (widget.taskBean?.sId == null) ? "新增成功" : "修改成功".toast(); diff --git a/lib/module/task/intime_log/intime_log_page.dart b/lib/module/task/intime_log/intime_log_page.dart index 0eee050..c9ca864 100644 --- a/lib/module/task/intime_log/intime_log_page.dart +++ b/lib/module/task/intime_log/intime_log_page.dart @@ -39,8 +39,7 @@ class _InTimeLogPageState extends State if (!canRequest) return; if (isRequest) return; isRequest = true; - HttpResponse response = - await Api.inTimeLog(widget.cronId); + HttpResponse response = await Api.inTimeLog(widget.cronId); if (response.success) { content = response.bean; setState(() {}); @@ -161,7 +160,7 @@ class _InTimeLogPageState extends State if (widget.needTimer) { _timer = Timer.periodic( const Duration(seconds: 2), - (timer) { + (timer) { getLogData(); }, ); diff --git a/lib/module/task/task_bean.dart b/lib/module/task/task_bean.dart index 97a9c3a..02faf57 100644 --- a/lib/module/task/task_bean.dart +++ b/lib/module/task/task_bean.dart @@ -26,20 +26,20 @@ class TaskBean { TaskBean( {this.name, - this.command, - this.schedule, - this.saved, - this.sId, - this.created, - this.status, - this.timestamp, - this.isSystem, - this.isDisabled, - this.logPath, - this.isPinned, - this.lastExecutionTime, - this.lastRunningTime, - this.pid}); + this.command, + this.schedule, + this.saved, + this.sId, + this.created, + this.status, + this.timestamp, + this.isSystem, + this.isDisabled, + this.logPath, + this.isPinned, + this.lastExecutionTime, + this.lastRunningTime, + this.pid}); get nId => _id; @@ -51,7 +51,9 @@ class TaskBean { saved = json['saved']; id = json['id']; _id = json['_id']; - sId = json.containsKey('_id') ? json['_id'].toString() : (json.containsKey('id') ? json['id'].toString() : ""); + sId = json.containsKey('_id') + ? json['_id'].toString() + : (json.containsKey('id') ? json['id'].toString() : ""); created = int.tryParse(json['created'].toString()); status = json['status']; timestamp = json['timestamp'].toString(); diff --git a/lib/module/task/task_detail/task_detail_page.dart b/lib/module/task/task_detail/task_detail_page.dart index ae19b57..083c7e6 100644 --- a/lib/module/task/task_detail/task_detail_page.dart +++ b/lib/module/task/task_detail/task_detail_page.dart @@ -17,7 +17,8 @@ class TaskDetailPage extends ConsumerStatefulWidget { final TaskBean taskBean; final bool hideAppbar; - const TaskDetailPage(this.taskBean, {Key? key, this.hideAppbar = false}) : super(key: key); + const TaskDetailPage(this.taskBean, {Key? key, this.hideAppbar = false}) + : super(key: key); @override _TaskDetailPageState createState() => _TaskDetailPageState(); @@ -71,11 +72,13 @@ class _TaskDetailPageState extends ConsumerState { ), TaskDetailCell( title: "创建时间", - desc: Utils.formatMessageTime(widget.taskBean.created ?? 0), + desc: + Utils.formatMessageTime(widget.taskBean.created ?? 0), ), TaskDetailCell( title: "更新时间", - desc: Utils.formatGMTTime(widget.taskBean.timestamp ?? ""), + desc: + Utils.formatGMTTime(widget.taskBean.timestamp ?? ""), ), TaskDetailCell( title: "任务定时", @@ -83,11 +86,14 @@ class _TaskDetailPageState extends ConsumerState { ), TaskDetailCell( title: "最后运行时间", - desc: Utils.formatMessageTime(widget.taskBean.lastExecutionTime ?? 0), + desc: Utils.formatMessageTime( + widget.taskBean.lastExecutionTime ?? 0), ), TaskDetailCell( title: "最后运行时长", - desc: widget.taskBean.lastRunningTime == null ? "-" : "${widget.taskBean.lastRunningTime ?? "-"}秒", + desc: widget.taskBean.lastRunningTime == null + ? "-" + : "${widget.taskBean.lastRunningTime ?? "-"}秒", ), GestureDetector( behavior: HitTestBehavior.opaque, @@ -205,7 +211,8 @@ class _TaskDetailPageState extends ConsumerState { behavior: HitTestBehavior.opaque, onTap: () { Navigator.of(context).pop(); - Navigator.of(context).pushNamed(Routes.routeAddTask, arguments: widget.taskBean); + Navigator.of(context) + .pushNamed(Routes.routeAddTask, arguments: widget.taskBean); }, child: Container( padding: const EdgeInsets.symmetric( @@ -357,12 +364,16 @@ class _TaskDetailPageState extends ConsumerState { } void enableTask() async { - await ref.read(taskProvider).enableTask(widget.taskBean.sId!, widget.taskBean.isDisabled!); + await ref + .read(taskProvider) + .enableTask(widget.taskBean.sId!, widget.taskBean.isDisabled!); setState(() {}); } void pinTask() async { - await ref.read(taskProvider).pinTask(widget.taskBean.sId!, widget.taskBean.isPinned!); + await ref + .read(taskProvider) + .pinTask(widget.taskBean.sId!, widget.taskBean.isPinned!); setState(() {}); } @@ -472,14 +483,16 @@ class TaskDetailCell extends ConsumerWidget { } }, style: TextStyle( - color: ref.watch(themeProvider).themeColor.descColor(), + color: + ref.watch(themeProvider).themeColor.descColor(), fontSize: 14, ), ), ), ) : Expanded( - child: Align(alignment: Alignment.centerRight, child: icon!), + child: + Align(alignment: Alignment.centerRight, child: icon!), ), ], ), diff --git a/lib/module/task/task_page.dart b/lib/module/task/task_page.dart index 6a5bce7..390ed3d 100644 --- a/lib/module/task/task_page.dart +++ b/lib/module/task/task_page.dart @@ -67,9 +67,17 @@ class _TaskPageState extends ConsumerState { } TaskBean item = list[index - 1]; 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(); @@ -80,9 +88,17 @@ class _TaskPageState extends ConsumerState { if (index == 0) return const SizedBox.shrink(); TaskBean item = list[index - 1]; 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 Container( color: ref.watch(themeProvider).themeColor.settingBgColor(), child: const Divider( @@ -130,7 +146,9 @@ class _TaskPageState extends ConsumerState { child: Text( TaskViewModel.allStr, style: TextStyle( - color: currentState == TaskViewModel.allStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + color: currentState == TaskViewModel.allStr + ? ref.watch(themeProvider).primaryColor + : ref.watch(themeProvider).themeColor.titleColor(), fontSize: 14, ), ), @@ -140,8 +158,9 @@ class _TaskPageState extends ConsumerState { child: Text( TaskViewModel.runningStr, style: TextStyle( - color: - currentState == TaskViewModel.runningStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + color: currentState == TaskViewModel.runningStr + ? ref.watch(themeProvider).primaryColor + : ref.watch(themeProvider).themeColor.titleColor(), fontSize: 14, ), ), @@ -151,7 +170,9 @@ class _TaskPageState extends ConsumerState { child: Text( TaskViewModel.neverStr, style: TextStyle( - color: currentState == TaskViewModel.neverStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + color: currentState == TaskViewModel.neverStr + ? ref.watch(themeProvider).primaryColor + : ref.watch(themeProvider).themeColor.titleColor(), fontSize: 14, ), ), @@ -165,7 +186,10 @@ class _TaskPageState extends ConsumerState { style: TextStyle( color: currentState == TaskViewModel.notScriptStr ? ref.watch(themeProvider).primaryColor - : ref.watch(themeProvider).themeColor.titleColor(), + : ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 14, ), ), @@ -178,8 +202,9 @@ class _TaskPageState extends ConsumerState { TaskViewModel.disableStr, style: TextStyle( fontSize: 14, - color: - currentState == TaskViewModel.disableStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(), + color: currentState == TaskViewModel.disableStr + ? ref.watch(themeProvider).primaryColor + : ref.watch(themeProvider).themeColor.titleColor(), ), ), value: TaskViewModel.disableStr, @@ -236,7 +261,9 @@ class TaskItemCell extends StatelessWidget { @override Widget build(BuildContext context) { return ColoredBox( - color: bean.isPinned == 1 ? ref.watch(themeProvider).themeColor.pinColor() : 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( @@ -247,7 +274,8 @@ class TaskItemCell extends StatelessWidget { backgroundColor: const Color(0xff5D5E70), onPressed: (_) { WidgetsBinding.instance.endOfFrame.then((timeStamp) { - Navigator.of(context).pushNamed(Routes.routeAddTask, arguments: bean); + Navigator.of(context) + .pushNamed(Routes.routeAddTask, arguments: bean); }); }, foregroundColor: Colors.white, @@ -259,7 +287,9 @@ class TaskItemCell extends StatelessWidget { pinTask(context); }, foregroundColor: Colors.white, - icon: (bean.isPinned ?? 0) == 0 ? CupertinoIcons.pin : CupertinoIcons.pin_slash, + icon: (bean.isPinned ?? 0) == 0 + ? CupertinoIcons.pin + : CupertinoIcons.pin_slash, ), SlidableAction( backgroundColor: const Color(0xffA356D6), @@ -267,7 +297,9 @@ class TaskItemCell extends StatelessWidget { enableTask(context); }, foregroundColor: Colors.white, - icon: bean.isDisabled! == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp, + icon: bean.isDisabled! == 0 + ? Icons.dnd_forwardslash + : Icons.check_circle_outline_sharp, ), SlidableAction( backgroundColor: const Color(0xffEA4D3E), @@ -299,7 +331,9 @@ class TaskItemCell extends StatelessWidget { } }, foregroundColor: Colors.white, - icon: bean.status! == 1 ? CupertinoIcons.memories : CupertinoIcons.stop_circle, + icon: bean.status! == 1 + ? CupertinoIcons.memories + : CupertinoIcons.stop_circle, ), SlidableAction( backgroundColor: const Color(0xff606467), @@ -317,10 +351,13 @@ class TaskItemCell extends StatelessWidget { ], ), child: Material( - color: bean.isPinned == 1 ? ref.watch(themeProvider).themeColor.pinColor() : 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); + Navigator.of(context) + .pushNamed(Routes.routeTaskDetail, arguments: bean); }, child: Container( width: MediaQuery.of(context).size.width, @@ -356,7 +393,10 @@ class TaskItemCell extends StatelessWidget { overflow: TextOverflow.ellipsis, style: TextStyle( overflow: TextOverflow.ellipsis, - color: ref.watch(themeProvider).themeColor.titleColor(), + color: ref + .watch(themeProvider) + .themeColor + .titleColor(), fontSize: 16, ), ), @@ -392,11 +432,16 @@ class TaskItemCell extends StatelessWidget { 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, ), ), diff --git a/lib/module/task/task_viewmodel.dart b/lib/module/task/task_viewmodel.dart index a2f7fd3..48ec5ed 100644 --- a/lib/module/task/task_viewmodel.dart +++ b/lib/module/task/task_viewmodel.dart @@ -62,7 +62,8 @@ class TaskViewModel extends BaseViewModel { } p.sort((TaskBean a, TaskBean b) { - bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0).isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0)); + bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0) + .isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0)); if (c == true) { return 1; } @@ -75,7 +76,8 @@ class TaskViewModel extends BaseViewModel { p.sort((a, b) { if (a.status == 0 && b.status == 0) { - bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0).isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0)); + bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0) + .isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0)); if (c == true) { return 1; } @@ -86,7 +88,8 @@ class TaskViewModel extends BaseViewModel { }); r.sort((a, b) { - bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0).isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0)); + bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0) + .isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0)); if (c == true) { return 1; } @@ -94,7 +97,8 @@ class TaskViewModel extends BaseViewModel { }); d.sort((a, b) { - bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0).isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0)); + bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0) + .isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0)); if (c == true) { return 1; } @@ -102,7 +106,8 @@ class TaskViewModel extends BaseViewModel { }); list.sort((a, b) { - bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0).isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0)); + bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0) + .isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0)); if (c == true) { return 1; } @@ -116,9 +121,12 @@ class TaskViewModel extends BaseViewModel { running.clear(); running.addAll(list.where((element) => element.status == 0)); neverRunning.clear(); - neverRunning.addAll(list.where((element) => element.lastRunningTime == null)); + neverRunning + .addAll(list.where((element) => element.lastRunningTime == null)); notScripts.clear(); - notScripts.addAll(list.where((element) => (element.command != null && (element.command!.startsWith("ql repo") || element.command!.startsWith("ql raw"))))); + notScripts.addAll(list.where((element) => (element.command != null && + (element.command!.startsWith("ql repo") || + element.command!.startsWith("ql raw"))))); disabled.clear(); disabled.addAll(list.where((element) => element.isDisabled == 1)); } diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 487886d..4d11b56 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -9,6 +9,7 @@ class Utils { static bool isUpperVersion() { return systemBean.isUpperVersion(); } + static bool isUpperVersion2_12_2() { return systemBean.isUpperVersion2_12_2(); } diff --git a/pub/code_field-master/example/lib/readme/fib.dart b/pub/code_field-master/example/lib/readme/fib.dart index cee4bba..2bf2908 100644 --- a/pub/code_field-master/example/lib/readme/fib.dart +++ b/pub/code_field-master/example/lib/readme/fib.dart @@ -2,12 +2,10 @@ // recursive implementation int fibonacci(int n) { if (n <= 1) return n; - return fibonacci(n - 1) - + fibonacci(n - 2); + return fibonacci(n - 1) + fibonacci(n - 2); } void main() { print("Fibonacci sequence:"); - for (var n = 0; n < 10; n++) - print(fibonacci(n)); + for (var n = 0; n < 10; n++) print(fibonacci(n)); } diff --git a/pub/code_field-master/lib/src/code_controller.dart b/pub/code_field-master/lib/src/code_controller.dart index 9cb5f02..e355ea0 100644 --- a/pub/code_field-master/lib/src/code_controller.dart +++ b/pub/code_field-master/lib/src/code_controller.dart @@ -64,7 +64,8 @@ class CodeController extends TextEditingController { this.onChange, }) : super(text: text) { // PatternMap - if (language != null && theme == null) throw Exception("A theme must be provided for language parsing"); + if (language != null && theme == null) + throw Exception("A theme must be provided for language parsing"); // Register language if (language != null) { highlight.registerLanguage(languageId, language!); @@ -152,7 +153,8 @@ class CodeController extends TextEditingController { const _chars = 'abcdefghijklmnopqrstuvwxyz1234567890'; final _rnd = Random(); return String.fromCharCodes( - Iterable.generate(10, (_) => _chars.codeUnitAt(_rnd.nextInt(_chars.length))), + Iterable.generate( + 10, (_) => _chars.codeUnitAt(_rnd.nextInt(_chars.length))), ); } @@ -178,8 +180,11 @@ class CodeController extends TextEditingController { } } // Now fix the textfield for web - if (_webSpaceFix) newValue = newValue.copyWith(text: _spacesToMiddleDots(newValue.text)); - if (onChange != null) onChange!(_webSpaceFix ? _middleDotsToSpaces(newValue.text) : newValue.text); + if (_webSpaceFix) + newValue = newValue.copyWith(text: _spacesToMiddleDots(newValue.text)); + if (onChange != null) + onChange!( + _webSpaceFix ? _middleDotsToSpaces(newValue.text) : newValue.text); super.value = newValue; } @@ -190,7 +195,11 @@ class CodeController extends TextEditingController { onMatch: (Match m) { if (styleList.isEmpty) return ''; int idx; - for (idx = 1; idx < m.groupCount && idx <= styleList.length && m.group(idx) == null; idx++) {} + for (idx = 1; + idx < m.groupCount && + idx <= styleList.length && + m.group(idx) == null; + idx++) {} children.add(TextSpan( text: m[0], style: styleList[idx - 1], @@ -221,7 +230,8 @@ class CodeController extends TextEditingController { if (val != null) { if (_webSpaceFix) val = _spacesToMiddleDots(val); var child = TextSpan(text: val, style: theme?[node.className]); - if (styleRegExp != null) child = _processPatterns(val, theme?[node.className]); + if (styleRegExp != null) + child = _processPatterns(val, theme?[node.className]); currentSpans.add(child); } else if (nodeChildren != null) { List tmp = []; @@ -245,7 +255,8 @@ class CodeController extends TextEditingController { } @override - TextSpan buildTextSpan({required BuildContext context, TextStyle? style, bool? withComposing}) { + TextSpan buildTextSpan( + {required BuildContext context, TextStyle? style, bool? withComposing}) { // Retrieve pattern regexp final patternList = []; if (_webSpaceFix) { diff --git a/pub/code_field-master/lib/src/code_field.dart b/pub/code_field-master/lib/src/code_field.dart index 7dc188d..fa442aa 100644 --- a/pub/code_field-master/lib/src/code_field.dart +++ b/pub/code_field-master/lib/src/code_field.dart @@ -12,14 +12,16 @@ class LineNumberController extends TextEditingController { LineNumberController(this.lineNumberBuilder); @override - TextSpan buildTextSpan({required BuildContext context, TextStyle? style, bool? withComposing}) { + TextSpan buildTextSpan( + {required BuildContext context, TextStyle? style, bool? withComposing}) { final children = []; final list = text.split("\n"); for (int k = 0; k < list.length; k++) { final el = list[k]; final number = int.parse(el); var textSpan = TextSpan(text: el, style: style); - if (lineNumberBuilder != null) textSpan = lineNumberBuilder!(number, style); + if (lineNumberBuilder != null) + textSpan = lineNumberBuilder!(number, style); children.add(textSpan); if (k < list.length - 1) children.add(TextSpan(text: "\n")); } @@ -199,7 +201,8 @@ class CodeFieldState extends State { } // Wrap the codeField in a horizontal scrollView - Widget _wrapInScrollView(Widget codeField, TextStyle textStyle, double minWidth) { + Widget _wrapInScrollView( + Widget codeField, TextStyle textStyle, double minWidth) { final leftPad = widget.lineNumberStyle.margin / 2; final intrinsic = IntrinsicWidth( child: Column( @@ -239,7 +242,8 @@ class CodeFieldState extends State { final defaultText = Colors.grey.shade200; final theme = widget.controller.theme; - Color? backgroundCol = widget.background ?? theme?[ROOT_KEY]?.backgroundColor ?? defaultBg; + Color? backgroundCol = + widget.background ?? theme?[ROOT_KEY]?.backgroundColor ?? defaultBg; if (widget.decoration != null) { backgroundCol = null; } @@ -249,14 +253,16 @@ class CodeFieldState extends State { fontSize: textStyle.fontSize ?? 16.0, ); TextStyle numberTextStyle = widget.lineNumberStyle.textStyle ?? TextStyle(); - final numberColor = (theme?[ROOT_KEY]?.color ?? defaultText).withOpacity(0.7); + final numberColor = + (theme?[ROOT_KEY]?.color ?? defaultText).withOpacity(0.7); // Copy important attributes numberTextStyle = numberTextStyle.copyWith( color: numberTextStyle.color ?? numberColor, fontSize: textStyle.fontSize, fontFamily: textStyle.fontFamily, ); - final cursorColor = widget.cursorColor ?? theme?[ROOT_KEY]?.color ?? defaultText; + final cursorColor = + widget.cursorColor ?? theme?[ROOT_KEY]?.color ?? defaultText; final lineNumberCol = TextField( smartQuotesType: widget.smartQuotesType, @@ -315,7 +321,9 @@ class CodeFieldState extends State { child: LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { // Control horizontal scrolling - return widget.wrap ? codeField : _wrapInScrollView(codeField, textStyle, constraints.maxWidth); + return widget.wrap + ? codeField + : _wrapInScrollView(codeField, textStyle, constraints.maxWidth); }, ), ); diff --git a/pub/code_field-master/lib/src/code_modifier.dart b/pub/code_field-master/lib/src/code_modifier.dart index 6239033..fdf4f8b 100644 --- a/pub/code_field-master/lib/src/code_modifier.dart +++ b/pub/code_field-master/lib/src/code_modifier.dart @@ -19,7 +19,8 @@ abstract class CodeModifier { ); } - TextEditingValue? updateString(String text, TextSelection sel, EditorParams params); + TextEditingValue? updateString( + String text, TextSelection sel, EditorParams params); } class IntendModifier extends CodeModifier { @@ -30,7 +31,8 @@ class IntendModifier extends CodeModifier { }) : super('\n'); @override - TextEditingValue? updateString(String text, TextSelection sel, EditorParams params) { + TextEditingValue? updateString( + String text, TextSelection sel, EditorParams params) { var spacesCount = 0; var braceCount = 0; for (var k = min(sel.start, text.length) - 1; k >= 0; k--) { @@ -53,7 +55,8 @@ class CloseBlockModifier extends CodeModifier { const CloseBlockModifier() : super('}'); @override - TextEditingValue? updateString(String text, TextSelection sel, EditorParams params) { + TextEditingValue? updateString( + String text, TextSelection sel, EditorParams params) { int spaceCount = 0; for (var k = min(sel.start, text.length) - 1; k >= 0; k--) { if (text[k] == "\n") break; @@ -63,7 +66,8 @@ class CloseBlockModifier extends CodeModifier { } spaceCount += 1; } - if (spaceCount >= params.tabSpaces) return replace(text, sel.start - params.tabSpaces, sel.end, "}"); + if (spaceCount >= params.tabSpaces) + return replace(text, sel.start - params.tabSpaces, sel.end, "}"); return null; } } @@ -72,7 +76,8 @@ class TabModifier extends CodeModifier { const TabModifier() : super('\t'); @override - TextEditingValue? updateString(String text, TextSelection sel, EditorParams params) { + TextEditingValue? updateString( + String text, TextSelection sel, EditorParams params) { final tmp = replace(text, sel.start, sel.end, " " * params.tabSpaces); return tmp; } diff --git a/pubspec.lock b/pubspec.lock index 3f155ec..e2a3af9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -239,6 +239,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "6.1.2" + file_picker: + dependency: "direct main" + description: + name: file_picker + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.6.1" fixnum: dependency: transitive description: @@ -312,6 +319,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.1.6" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.6" flutter_riverpod: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 2a2d778..0f31f47 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,6 +37,7 @@ dependencies: share_plus: ^4.0.7 flutter_animator: ^3.2.1 modal_bottom_sheet: ^2.0.1 + file_picker: ^4.6.1 code_text_field: path: ./pub/code_field-master diff --git a/test/widget_test.dart b/test/widget_test.dart index baa5890..570e0e4 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -5,6 +5,4 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -void main() { - -} +void main() {}