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 ## v1.0.6
* 支持切换账号功能 * 支持切换账号功能
* 登录页青龙图标随颜色主题变换 * 登录页青龙图标随颜色主题变换

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
import 'package:dio_log/dio_log.dart'; import 'package:dio_log/dio_log.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qinglong_app/base/http/api.dart'; import 'package:qinglong_app/base/http/api.dart';
import 'package:qinglong_app/base/http/http.dart'; import 'package:qinglong_app/base/http/http.dart';
@@ -74,336 +75,339 @@ class _LoginPageState extends ConsumerState<LoginPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeArea( return Scaffold(
child: ColoredBox( body: AnnotatedRegion<SystemUiOverlayStyle>(
color: ref.watch(themeProvider).themeColor.settingBgColor(), value: ref.watch(themeProvider).darkMode == true ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
child: SizedBox( child: ColoredBox(
height: MediaQuery.of(context).size.height, color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: Stack( child: SizedBox(
children: [ height: MediaQuery.of(context).size.height,
Positioned( child: Stack(
bottom: 0, children: [
child: Image.asset( Positioned(
"assets/images/login_bg.png", bottom: 0,
width: MediaQuery.of(context).size.width, 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,
),
],
), ),
), ),
), Scaffold(
Positioned( backgroundColor: Colors.transparent,
bottom: 10, body: SingleChildScrollView(
child: (getIt<UserInfoViewModel>().historyAccounts.isEmpty) child: Column(
? const SizedBox.shrink() mainAxisAlignment: MainAxisAlignment.start,
: SizedBox( crossAxisAlignment: CrossAxisAlignment.start,
width: MediaQuery.of(context).size.width, children: [
child: Center( Padding(
child: Material( padding: const EdgeInsets.symmetric(
color: Colors.transparent, horizontal: 40,
child: PopupMenuButton<UserInfoBean>( ),
onSelected: (UserInfoBean result) { child: Column(
selected(result); mainAxisAlignment: MainAxisAlignment.start,
}, crossAxisAlignment: CrossAxisAlignment.start,
itemBuilder: (BuildContext context) => <PopupMenuEntry<UserInfoBean>>[ children: [
...getIt<UserInfoViewModel>() SizedBox(
.historyAccounts height: MediaQuery.of(context).size.height / 10,
.map((e) => PopupMenuItem<UserInfoBean>( ),
value: e, Row(
child: buildCell(e), children: [
)) Expanded(
.toList(), child: Align(
], alignment: Alignment.centerLeft,
child: Text( 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( style: TextStyle(
color: ref.watch(themeProvider).primaryColor,
fontSize: 14, 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: "从未运行", text: "从未运行",
), ),
Tab( Tab(
text: "脚本", text: "拉库脚本",
), ),
Tab( Tab(
text: "已禁用", text: "已禁用",

View File

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

View File

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

View File

@@ -1 +1 @@
1.0.6 1.0.7