Merge pull request #2 from qinglong-app/dev

Dev
This commit is contained in:
NewTab
2022-02-21 14:45:29 +08:00
committed by GitHub
9 changed files with 363 additions and 344 deletions

View File

@ -1,3 +1,8 @@
## v1.0.7
* 首页任务增加分类
* 增加国际化相关配置
* 登录页状态栏适配
## v1.0.6
* 支持切换账号功能
* 登录页青龙图标随颜色主题变换

View File

@ -38,6 +38,9 @@ iOS端暂无上架打算用户自行下载main分支源码编译安装
<img src="./art/8.jpg" width="200" />
</p>
## [更新记录](./CHANGELOG.md)
### 不支持的功能
>* 应用设置
>* 通知设置

View File

@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()

View File

@ -10,6 +10,7 @@ import 'package:logger/logger.dart';
import 'package:qinglong_app/base/theme.dart';
import 'package:qinglong_app/module/login/login_page.dart';
import 'package:qinglong_app/utils/sp_utils.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'base/routes.dart';
import 'base/userinfo_viewmodel.dart';
@ -34,8 +35,7 @@ void main() async {
),
);
if (Platform.isAndroid) {
SystemUiOverlayStyle style =
const SystemUiOverlayStyle(statusBarColor: Colors.transparent);
SystemUiOverlayStyle style = const SystemUiOverlayStyle(statusBarColor: Colors.transparent);
SystemChrome.setSystemUIOverlayStyle(style);
}
}
@ -56,14 +56,22 @@ class QlAppState extends ConsumerState<QlApp> {
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(
title: "青龙",
locale: const Locale('zh', 'CN'),
navigatorKey: navigatorState,
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('zh', 'CN'),
Locale('en', 'US'),
],
theme: ref.watch<ThemeViewModel>(themeProvider).currentTheme,
onGenerateRoute: (setting) {
return Routes.generateRoute(setting);
@ -73,9 +81,7 @@ class QlAppState extends ConsumerState<QlApp> {
if (!kReleaseMode) {
showDebugBtn(context);
}
return getIt<UserInfoViewModel>().isLogined()
? const HomePage()
: const LoginPage();
return getIt<UserInfoViewModel>().isLogined() ? const HomePage() : const LoginPage();
},
),
// home: LoginPage(),

View File

@ -1,6 +1,7 @@
import 'package:dio_log/dio_log.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qinglong_app/base/http/api.dart';
import 'package:qinglong_app/base/http/http.dart';
@ -74,336 +75,339 @@ class _LoginPageState extends ConsumerState<LoginPage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: ColoredBox(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
Positioned(
bottom: 0,
child: Image.asset(
"assets/images/login_bg.png",
width: MediaQuery.of(context).size.width,
),
),
Scaffold(
backgroundColor: Colors.transparent,
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 40,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: MediaQuery.of(context).size.height / 10,
),
Row(
children: [
Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: Image.asset(
"assets/images/login_tip.png",
height: 45,
),
),
),
GestureDetector(
onDoubleTap: () {
if (debugBtnIsShow()) {
dismissDebugBtn();
} else {
showDebugBtn(context, btnColor: ref.watch(themeProvider).primaryColor);
}
WidgetsBinding.instance?.endOfFrame;
},
child: ColorFiltered(
colorFilter: ColorFilter.mode(
ref.watch(themeProvider).primaryColor,
BlendMode.srcIn,
),
child: Image.asset(
"assets/images/ql.png",
height: 45,
),
),
),
],
),
SizedBox(
height: MediaQuery.of(context).size.height / 15,
),
const Text(
"域名:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
onChanged: (_) {
setState(() {});
},
controller: _hostController,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "http://1.1.1.1:5700",
),
autofocus: false,
),
FlipCard(
key: cardKey,
flipOnTouch: false,
onFlipDone: (back) {
useSecretLogin = back;
setState(() {});
},
direction: FlipDirection.HORIZONTAL,
front: SizedBox(
height: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 15,
),
const Text(
"用户名:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
onChanged: (_) {
setState(() {});
},
controller: _userNameController,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入用户名",
),
autofocus: false,
),
const SizedBox(
height: 15,
),
const Text(
"密码:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
onChanged: (_) {
setState(() {});
},
controller: _passwordController,
obscureText: true,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入密码",
),
autofocus: false,
),
const SizedBox(
height: 10,
),
],
),
),
back: SizedBox(
height: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 15,
),
const Text(
"client_id:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
onChanged: (_) {
setState(() {});
},
controller: _cIdController,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入client_id",
),
autofocus: false,
),
const SizedBox(
height: 15,
),
const Text(
"client_secret:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
onChanged: (_) {
setState(() {});
},
controller: _cSecretController,
obscureText: true,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入client_secret",
),
autofocus: false,
),
const SizedBox(
height: 10,
),
],
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 25,
),
child: Row(
children: [
Checkbox(
value: rememberPassword,
onChanged: (checked) {
rememberPassword = checked ?? false;
setState(() {});
},
),
const Text(
"记住密码/client",
style: TextStyle(
fontSize: 14,
),
),
const Spacer(),
GestureDetector(
onTap: () {
cardKey.currentState?.toggleCard();
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
setState(() {});
});
},
child: Text(
loginByUserName() ? "client_id登录" : "账号登录",
style: const TextStyle(
fontSize: 14,
),
),
),
const SizedBox(
width: 10,
),
],
),
),
const SizedBox(
height: 30,
),
Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(
horizontal: 40,
),
child: SizedBox(
width: MediaQuery.of(context).size.width - 80,
child: IgnorePointer(
ignoring: !canClickLoginBtn(),
child: CupertinoButton(
padding: const EdgeInsets.symmetric(
vertical: 5,
),
color: canClickLoginBtn() ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).primaryColor.withOpacity(0.4),
child: isLoading
? const CupertinoActivityIndicator()
: const Text(
"登 录",
style: TextStyle(
fontSize: 16,
),
),
onPressed: () {
Http.pushedLoginPage = false;
Utils.hideKeyBoard(context);
if (loginByUserName()) {
login(_userNameController.text, _passwordController.text);
} else {
login(_cIdController.text, _cSecretController.text);
}
},
),
),
),
),
const SizedBox(
height: 30,
),
],
return Scaffold(
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: ref.watch(themeProvider).darkMode == true ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
child: ColoredBox(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
Positioned(
bottom: 0,
child: Image.asset(
"assets/images/login_bg.png",
width: MediaQuery.of(context).size.width,
),
),
),
Positioned(
bottom: 10,
child: (getIt<UserInfoViewModel>().historyAccounts.isEmpty)
? const SizedBox.shrink()
: SizedBox(
width: MediaQuery.of(context).size.width,
child: Center(
child: Material(
color: Colors.transparent,
child: PopupMenuButton<UserInfoBean>(
onSelected: (UserInfoBean result) {
selected(result);
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<UserInfoBean>>[
...getIt<UserInfoViewModel>()
.historyAccounts
.map((e) => PopupMenuItem<UserInfoBean>(
value: e,
child: buildCell(e),
))
.toList(),
],
child: Text(
"切换账号",
Scaffold(
backgroundColor: Colors.transparent,
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 40,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: MediaQuery.of(context).size.height / 10,
),
Row(
children: [
Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: Image.asset(
"assets/images/login_tip.png",
height: 45,
),
),
),
GestureDetector(
onDoubleTap: () {
if (debugBtnIsShow()) {
dismissDebugBtn();
} else {
showDebugBtn(context, btnColor: ref.watch(themeProvider).primaryColor);
}
WidgetsBinding.instance?.endOfFrame;
},
child: ColorFiltered(
colorFilter: ColorFilter.mode(
ref.watch(themeProvider).primaryColor,
BlendMode.srcIn,
),
child: Image.asset(
"assets/images/ql.png",
height: 45,
),
),
),
],
),
SizedBox(
height: MediaQuery.of(context).size.height / 15,
),
const Text(
"域名:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
onChanged: (_) {
setState(() {});
},
controller: _hostController,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "http://1.1.1.1:5700",
),
autofocus: false,
),
FlipCard(
key: cardKey,
flipOnTouch: false,
onFlipDone: (back) {
useSecretLogin = back;
setState(() {});
},
direction: FlipDirection.HORIZONTAL,
front: SizedBox(
height: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 15,
),
const Text(
"用户名:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
onChanged: (_) {
setState(() {});
},
controller: _userNameController,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入用户名",
),
autofocus: false,
),
const SizedBox(
height: 15,
),
const Text(
"密码:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
onChanged: (_) {
setState(() {});
},
controller: _passwordController,
obscureText: true,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入密码",
),
autofocus: false,
),
const SizedBox(
height: 10,
),
],
),
),
back: SizedBox(
height: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 15,
),
const Text(
"client_id:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
onChanged: (_) {
setState(() {});
},
controller: _cIdController,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入client_id",
),
autofocus: false,
),
const SizedBox(
height: 15,
),
const Text(
"client_secret:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
onChanged: (_) {
setState(() {});
},
controller: _cSecretController,
obscureText: true,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入client_secret",
),
autofocus: false,
),
const SizedBox(
height: 10,
),
],
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 25,
),
child: Row(
children: [
Checkbox(
value: rememberPassword,
onChanged: (checked) {
rememberPassword = checked ?? false;
setState(() {});
},
),
const Text(
"记住密码/client",
style: TextStyle(
color: ref.watch(themeProvider).primaryColor,
fontSize: 14,
),
),
const Spacer(),
GestureDetector(
onTap: () {
cardKey.currentState?.toggleCard();
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
setState(() {});
});
},
child: Text(
loginByUserName() ? "client_id登录" : "账号登录",
style: const TextStyle(
fontSize: 14,
),
),
),
const SizedBox(
width: 10,
),
],
),
),
const SizedBox(
height: 30,
),
Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(
horizontal: 40,
),
child: SizedBox(
width: MediaQuery.of(context).size.width - 80,
child: IgnorePointer(
ignoring: !canClickLoginBtn(),
child: CupertinoButton(
padding: const EdgeInsets.symmetric(
vertical: 5,
),
color: canClickLoginBtn() ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).primaryColor.withOpacity(0.4),
child: isLoading
? const CupertinoActivityIndicator()
: const Text(
"登 录",
style: TextStyle(
fontSize: 16,
),
),
onPressed: () {
Http.pushedLoginPage = false;
Utils.hideKeyBoard(context);
if (loginByUserName()) {
login(_userNameController.text, _passwordController.text);
} else {
login(_cIdController.text, _cSecretController.text);
}
},
),
),
),
),
const SizedBox(
height: 30,
),
],
),
),
),
Positioned(
bottom: 10,
child: (getIt<UserInfoViewModel>().historyAccounts.isEmpty)
? const SizedBox.shrink()
: SizedBox(
width: MediaQuery.of(context).size.width,
child: Center(
child: Material(
color: Colors.transparent,
child: PopupMenuButton<UserInfoBean>(
onSelected: (UserInfoBean result) {
selected(result);
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<UserInfoBean>>[
...getIt<UserInfoViewModel>()
.historyAccounts
.map((e) => PopupMenuItem<UserInfoBean>(
value: e,
child: buildCell(e),
))
.toList(),
],
child: Text(
"切换账号",
style: TextStyle(
color: ref.watch(themeProvider).primaryColor,
fontSize: 14,
),
),
),
),
),
),
),
),
],
),
],
),
),
),
),

View File

@ -57,7 +57,7 @@ class _TaskPageState extends State<TaskPage> {
text: "从未运行",
),
Tab(
text: "脚本",
text: "拉库脚本",
),
Tab(
text: "已禁用",

View File

@ -43,7 +43,7 @@ class TaskViewModel extends BaseViewModel {
running.clear();
running.addAll(list.where((element) => element.status == 0));
neverRunning.clear();
neverRunning.addAll(list.where((element) => element.lastRunningTime == null || element.lastRunningTime == 0));
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")))));
disabled.clear();

View File

@ -1,20 +1,21 @@
name: qinglong_app
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.6+8
version: 1.0.7+9
environment:
sdk: ">=2.15.1 <3.0.0"
flutter: ">=2.8.1"
flutter: ">=2.10.1"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
flutter_localizations:
sdk: flutter
cupertino_icons: ^1.0.4
flutter_riverpod: ^1.0.3
shared_preferences: ^2.0.12
shared_preferences: ^2.0.13
synchronized: ^3.0.0
back_button_interceptor: ^5.0.2
flutter_slidable: ^1.2.0
@ -29,23 +30,23 @@ dependencies:
fluttertoast: ^8.0.8
move_to_background: ^1.0.2
flip_card: ^0.6.0
package_info_plus: ^1.3.0
url_launcher: ^6.0.18
package_info_plus: ^1.4.0
url_launcher: ^6.0.20
flutter_colorpicker: ^1.0.3
dev_dependencies:
flutter_native_splash: ^1.3.3
flutter_native_splash: ^2.0.5
flutter_launcher_icons: ^0.9.2
change_app_package_name: ^0.1.3
flutter_app_name: ^0.1.0
change_app_package_name: ^1.0.0
flutter_app_name: ^0.1.1
build_runner: ^2.0.0
build_runner: ^2.1.7
json_conversion: ^0.0.4
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
flutter_lints: ^1.0.4
flutter:

View File

@ -1 +1 @@
1.0.6
1.0.7