11 Commits

Author SHA1 Message Date
jyuesong
c7824c920b 优化使用体验 2022-06-02 08:37:54 +08:00
jyuesong
817ad978e2 修改logo 2022-05-30 16:41:47 +08:00
jyuesong
1d59128e47 修改logo 2022-05-30 14:25:32 +08:00
jyuesong
62537f5814 强制横屏 2022-05-30 14:22:09 +08:00
jyuesong
5f91160d9a 强制横屏 2022-05-30 14:20:20 +08:00
jyuesong
64ee8189b1 更新app name 2022-05-30 14:16:37 +08:00
jyuesong
665a51f962 同步ios的功能 2022-05-30 14:14:49 +08:00
jyuesong
bd77beb60a 同步ios的功能 2022-05-30 14:02:14 +08:00
jyuesong
578bb926fa 优化任务列表,环境变量 2022-05-30 13:04:33 +08:00
jyuesong
2c64038fda 任务列表优化 2022-05-30 10:41:09 +08:00
jyuesong
9a27ae8e69 任务列表排序 2022-05-27 09:59:15 +08:00
121 changed files with 1434 additions and 4047 deletions

View File

@@ -44,3 +44,20 @@ iOS端暂无上架打算用户自行下载main分支源码编译安装
### 不支持的功能
>* 应用设置
>* 通知设置
版本更新通知 https://t.me/qinglongapp
用于生成app的图标
flutter pub run flutter_launcher_icons:main
生成原生的启动页面
flutter pub run flutter_native_splash:create
修改app名称
flutter pub run flutter_app_name
生成json.jc.dart文件
flutter pub run build_runner build --delete-conflicting-outputs

View File

@@ -3,7 +3,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="青龙"
android:label="青龙客户端"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/images/ql_splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

34
ios/.gitignore vendored
View File

@@ -1,34 +0,0 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
</dict>
</plist>

View File

@@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View File

@@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

View File

@@ -1,41 +0,0 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

View File

@@ -1,65 +0,0 @@
PODS:
- Flutter (1.0.0)
- flutter_native_splash (0.0.1):
- Flutter
- fluttertoast (0.0.2):
- Flutter
- Toast
- move_to_background (0.0.1):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_ios (0.0.1):
- Flutter
- shared_preferences_ios (0.0.1):
- Flutter
- Toast (4.0.0)
- url_launcher_ios (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- move_to_background (from `.symlinks/plugins/move_to_background/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
trunk:
- Toast
EXTERNAL SOURCES:
Flutter:
:path: Flutter
flutter_native_splash:
:path: ".symlinks/plugins/flutter_native_splash/ios"
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
move_to_background:
:path: ".symlinks/plugins/move_to_background/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_ios:
:path: ".symlinks/plugins/path_provider_ios/ios"
shared_preferences_ios:
:path: ".symlinks/plugins/shared_preferences_ios/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
fluttertoast: 16fbe6039d06a763f3533670197d01fc73459037
move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
COCOAPODS: 1.11.2

View File

@@ -1,554 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
2861C45503C8372CCC7FCAA2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E0C7852E889B34711E51EF29 /* Pods_Runner.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
08A8D0920911B337FB46E8F3 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
423DC651AE7A04B8898F3FDB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D8C98252A2BD23DF365AF3A8 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
E0C7852E889B34711E51EF29 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2861C45503C8372CCC7FCAA2 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
80959B63BA92AC28CD093868 /* Frameworks */ = {
isa = PBXGroup;
children = (
E0C7852E889B34711E51EF29 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
BA4BC66201CBD612BFBB5DAE /* Pods */,
80959B63BA92AC28CD093868 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
BA4BC66201CBD612BFBB5DAE /* Pods */ = {
isa = PBXGroup;
children = (
D8C98252A2BD23DF365AF3A8 /* Pods-Runner.debug.xcconfig */,
423DC651AE7A04B8898F3FDB /* Pods-Runner.release.xcconfig */,
08A8D0920911B337FB46E8F3 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
FD0948CDBEBEC8A5B7ABF83F /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
C4AE37104D47B22A99900CA3 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
C4AE37104D47B22A99900CA3 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
FD0948CDBEBEC8A5B7ABF83F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = MKUK6TT46Z;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = work.master.qinglongApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = MKUK6TT46Z;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = work.master.qinglongApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = MKUK6TT46Z;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = work.newtab.qinglongApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@@ -1,87 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@@ -1,13 +0,0 @@
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@@ -1,122 +0,0 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -1,52 +0,0 @@
{
"images" : [
{
"filename" : "background.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "darkbackground.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 B

View File

@@ -1,23 +0,0 @@
{
"images" : [
{
"filename" : "LaunchImage.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "LaunchImage@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "LaunchImage@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -1,5 +0,0 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="3T2-ad-Qdv"/>
<constraint firstItem="tWc-Dq-wcI" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="RPx-PI-7Xg"/>
<constraint firstItem="tWc-Dq-wcI" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="SdS-ul-q2q"/>
<constraint firstAttribute="trailing" secondItem="tWc-Dq-wcI" secondAttribute="trailing" id="Swv-Gf-Rwn"/>
<constraint firstAttribute="trailing" secondItem="YRO-k0-Ey4" secondAttribute="trailing" id="TQA-XW-tRk"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="duK-uY-Gun"/>
<constraint firstItem="tWc-Dq-wcI" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="kV7-tw-vXt"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="xPn-NY-SIU"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="240" height="240"/>
<image name="LaunchBackground" width="1" height="1"/>
</resources>
</document>

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>青龙</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>青龙</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<false/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@@ -1 +0,0 @@
#import "GeneratedPluginRegistrant.h"

View File

@@ -1,4 +1,6 @@
import 'package:qinglong_app/base/http/http.dart';
import 'package:qinglong_app/base/http/url.dart';
import 'package:qinglong_app/main.dart';
import 'package:qinglong_app/module/config/config_bean.dart';
import 'package:qinglong_app/module/env/env_bean.dart';
import 'package:qinglong_app/module/home/system_bean.dart';
@@ -9,9 +11,7 @@ import 'package:qinglong_app/module/others/login_log/login_log_bean.dart';
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';
import '../../utils/utils.dart';
import 'url.dart';
import 'package:qinglong_app/utils/utils.dart';
class Api {
static Future<HttpResponse<SystemBean>> system() async {
@@ -89,24 +89,21 @@ class Api {
);
}
static Future<HttpResponse<NullResponse>> startTasks(
List<String> crons) async {
static Future<HttpResponse<NullResponse>> startTasks(List<String> crons) async {
return await Http.put<NullResponse>(
Url.runTasks,
crons,
);
}
static Future<HttpResponse<NullResponse>> stopTasks(
List<String> crons) async {
static Future<HttpResponse<NullResponse>> stopTasks(List<String> crons) async {
return await Http.put<NullResponse>(
Url.stopTasks,
crons,
);
}
static Future<HttpResponse<NullResponse>> updatePassword(
String name, String password) async {
static Future<HttpResponse<NullResponse>> updatePassword(String name, String password) async {
return await Http.put<NullResponse>(
Url.updatePassword,
{
@@ -124,15 +121,19 @@ class Api {
}
static Future<HttpResponse<NullResponse>> addTask(
String name, String command, String cron,
{String? id}) async {
var data = {"name": name, "command": command, "schedule": cron};
String name,
String command,
String cron, {
int? id,
String? nId,
}) async {
var data = <String, dynamic>{"name": name, "command": command, "schedule": cron};
if (id != null) {
if (Utils.isUpperVersion()) {
if (id != null || nId != null) {
if (id != null) {
data["id"] = id;
} else {
data["_id"] = id;
} else if (nId != null) {
data["_id"] = nId;
}
return await Http.put<NullResponse>(
Url.addTask,
@@ -194,8 +195,7 @@ class Api {
);
}
static Future<HttpResponse<NullResponse>> saveFile(
String name, String content) async {
static Future<HttpResponse<NullResponse>> saveFile(String name, String content) async {
return await Http.post<NullResponse>(
Url.saveFile,
{"content": content, "name": name},
@@ -231,21 +231,24 @@ class Api {
}
static Future<HttpResponse<NullResponse>> addEnv(
String name, String value, String remarks,
{String? id}) async {
var data = {
String name,
String value,
String remarks, {
int? id,
String? nId,
}) async {
var data = <String, dynamic>{
"value": value,
"remarks": remarks,
"name": name,
};
if (id != null) {
if (Utils.isUpperVersion()) {
if (id != null || nId != null) {
if (id != null) {
data["id"] = id;
} else {
data["_id"] = id;
} else if (nId != null) {
data["_id"] = nId;
}
return await Http.put<NullResponse>(
Url.addEnv,
data,
@@ -257,8 +260,7 @@ class Api {
);
}
static Future<HttpResponse<NullResponse>> moveEnv(
String id, int fromIndex, int toIndex) async {
static Future<HttpResponse<NullResponse>> moveEnv(String id, int fromIndex, int toIndex) async {
return await Http.put<NullResponse>(
Url.envMove(id),
{"fromIndex": fromIndex, "toIndex": toIndex},
@@ -273,26 +275,32 @@ class Api {
}
static Future<HttpResponse<List<TaskLogBean>>> taskLog() async {
return await Http.get<List<TaskLogBean>>(Url.taskLog, null,
serializationName: "dirs");
return await Http.get<List<TaskLogBean>>(Url.taskLog, null, serializationName: Utils.isUpperVersion2_12_2() ? "data" : "dirs");
}
static Future<HttpResponse<String>> taskLogDetail(String name) async {
return await Http.get<String>(
Url.taskLogDetail + name,
null,
);
static Future<HttpResponse<String>> taskLogDetail(String name, String path) async {
if (Utils.isUpperVersion2_13_0()) {
return await Http.get<String>(
Url.taskLogDetail + name + "?path=" + path,
null,
);
} else {
return await Http.get<String>(
Url.taskLogDetail + path + "/" + name,
null,
);
}
}
static Future<HttpResponse<List<ScriptBean>>> scripts() async {
//2.12.2以及以上版本,脚本路径url做了修改
return await Http.get<List<ScriptBean>>(
Url.scripts,
Utils.isUpperVersion2_13_0() ? Url.scripts2 : Url.scripts,
null,
);
}
static Future<HttpResponse<NullResponse>> updateScript(
String name, String path, String content) async {
static Future<HttpResponse<NullResponse>> updateScript(String name, String path, String content) async {
return await Http.put<NullResponse>(
Url.scriptDetail,
{
@@ -303,8 +311,7 @@ class Api {
);
}
static Future<HttpResponse<NullResponse>> delScript(
String name, String path) async {
static Future<HttpResponse<NullResponse>> delScript(String name, String path) async {
return await Http.delete<NullResponse>(
Url.scriptDetail,
{
@@ -314,8 +321,7 @@ class Api {
);
}
static Future<HttpResponse<String>> scriptDetail(
String name, String? path) async {
static Future<HttpResponse<String>> scriptDetail(String name, String? path) async {
return await Http.get<String>(
Url.scriptDetail + name,
{
@@ -324,8 +330,7 @@ class Api {
);
}
static Future<HttpResponse<List<DependencyBean>>> dependencies(
String type) async {
static Future<HttpResponse<List<DependencyBean>>> dependencies(String type) async {
return await Http.get<List<DependencyBean>>(
Url.dependencies,
{
@@ -334,8 +339,7 @@ class Api {
);
}
static Future<HttpResponse<NullResponse>> dependencyReinstall(
String id) async {
static Future<HttpResponse<NullResponse>> dependencyReinstall(String id) async {
return await Http.put<NullResponse>(
Url.dependencies,
[id],
@@ -349,8 +353,7 @@ class Api {
);
}
static Future<HttpResponse<NullResponse>> addDependency(
String name, int type) async {
static Future<HttpResponse<NullResponse>> addDependency(String name, int type) async {
return await Http.post<NullResponse>(
Url.dependencies,
[
@@ -362,6 +365,17 @@ class Api {
);
}
static Future<HttpResponse<NullResponse>> addScript(String name, String path, String content) async {
return await Http.post<NullResponse>(
Url.addScript,
{
"filename": name,
"path": path,
"content": content,
},
);
}
static Future<HttpResponse<NullResponse>> delDependency(String id) async {
return await Http.delete<NullResponse>(
Url.dependencies,

View File

@@ -8,7 +8,7 @@ class TokenInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
options.headers["User-Agent"] =
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1";
"qinglong_client";
options.headers["Content-Type"] = "application/json;charset=UTF-8";

View File

@@ -1,11 +1,11 @@
import '../../main.dart';
import '../userinfo_viewmodel.dart';
import 'package:qinglong_app/base/userinfo_viewmodel.dart';
import 'package:qinglong_app/main.dart';
class Url {
static get system => "/api/system";
static get login => "/api/user/login";
static get system => "/api/system";
static get loginOld => "/api/login";
static get loginTwo => "/api/user/two-factor/login";
@@ -14,119 +14,70 @@ class Url {
static const updatePassword = "/api/user";
static get tasks => getIt<UserInfoViewModel>().useSecretLogined
? "/open/crons"
: "/api/crons";
static get tasks => getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons" : "/api/crons";
static get runTasks => getIt<UserInfoViewModel>().useSecretLogined
? "/open/crons/run"
: "/api/crons/run";
static get runTasks => getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons/run" : "/api/crons/run";
static get stopTasks => getIt<UserInfoViewModel>().useSecretLogined
? "/open/crons/stop"
: "/api/crons/stop";
static get stopTasks => getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons/stop" : "/api/crons/stop";
static get taskDetail => getIt<UserInfoViewModel>().useSecretLogined
? "/open/crons/"
: "/api/crons/";
static get taskDetail => getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons/" : "/api/crons/";
static get addTask => getIt<UserInfoViewModel>().useSecretLogined
? "/open/crons"
: "/api/crons";
static get addTask => getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons" : "/api/crons";
static get pinTask => getIt<UserInfoViewModel>().useSecretLogined
? "/open/crons/pin"
: "/api/crons/pin";
static get pinTask => getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons/pin" : "/api/crons/pin";
static get unpinTask => getIt<UserInfoViewModel>().useSecretLogined
? "/open/crons/unpin"
: "/api/crons/unpin";
static get unpinTask => getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons/unpin" : "/api/crons/unpin";
static get enableTask => getIt<UserInfoViewModel>().useSecretLogined
? "/open/crons/enable"
: "/api/crons/enable";
static get enableTask => getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons/enable" : "/api/crons/enable";
static get disableTask => getIt<UserInfoViewModel>().useSecretLogined
? "/open/crons/disable"
: "/api/crons/disable";
static get disableTask => getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons/disable" : "/api/crons/disable";
static get files => getIt<UserInfoViewModel>().useSecretLogined
? "/open/configs/files"
: "/api/configs/files";
static get files => getIt<UserInfoViewModel>().useSecretLogined ? "/open/configs/files" : "/api/configs/files";
static get configContent => getIt<UserInfoViewModel>().useSecretLogined
? "/open/configs/"
: "/api/configs/";
static get configContent => getIt<UserInfoViewModel>().useSecretLogined ? "/open/configs/" : "/api/configs/";
static get saveFile => getIt<UserInfoViewModel>().useSecretLogined
? "/open/configs/save"
: "/api/configs/save";
static get saveFile => getIt<UserInfoViewModel>().useSecretLogined ? "/open/configs/save" : "/api/configs/save";
static get envs =>
getIt<UserInfoViewModel>().useSecretLogined ? "/open/envs" : "/api/envs";
static get envs => getIt<UserInfoViewModel>().useSecretLogined ? "/open/envs" : "/api/envs";
static get addEnv =>
getIt<UserInfoViewModel>().useSecretLogined ? "/open/envs" : "/api/envs";
static get addEnv => getIt<UserInfoViewModel>().useSecretLogined ? "/open/envs" : "/api/envs";
static get delEnv =>
getIt<UserInfoViewModel>().useSecretLogined ? "/open/envs" : "/api/envs";
static get delEnv => getIt<UserInfoViewModel>().useSecretLogined ? "/open/envs" : "/api/envs";
static get disableEnvs => getIt<UserInfoViewModel>().useSecretLogined
? "/open/envs/disable"
: "/api/envs/disable";
static get disableEnvs => getIt<UserInfoViewModel>().useSecretLogined ? "/open/envs/disable" : "/api/envs/disable";
static get enableEnvs => getIt<UserInfoViewModel>().useSecretLogined
? "/open/envs/enable"
: "/api/envs/enable";
static get enableEnvs => getIt<UserInfoViewModel>().useSecretLogined ? "/open/envs/enable" : "/api/envs/enable";
static get loginLog => getIt<UserInfoViewModel>().useSecretLogined
? "/open/user/login-log"
: "/api/user/login-log";
static get loginLog => getIt<UserInfoViewModel>().useSecretLogined ? "/open/user/login-log" : "/api/user/login-log";
static get taskLog =>
getIt<UserInfoViewModel>().useSecretLogined ? "/open/logs" : "/api/logs";
static get taskLog => getIt<UserInfoViewModel>().useSecretLogined ? "/open/logs" : "/api/logs";
static get taskLogDetail => getIt<UserInfoViewModel>().useSecretLogined
? "/open/logs/"
: "/api/logs/";
static get taskLogDetail => getIt<UserInfoViewModel>().useSecretLogined ? "/open/logs/" : "/api/logs/";
static get scripts => getIt<UserInfoViewModel>().useSecretLogined
? "/open/scripts/files"
: "/api/scripts/files";
static get scripts => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts/files" : "/api/scripts/files";
static get scriptUpdate => getIt<UserInfoViewModel>().useSecretLogined
? "/open/scripts"
: "/api/scripts";
static get scripts2 => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts" : "/api/scripts";
static get scriptDetail => getIt<UserInfoViewModel>().useSecretLogined
? "/open/scripts/"
: "/api/scripts/";
static get scriptUpdate => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts" : "/api/scripts";
static get dependencies => getIt<UserInfoViewModel>().useSecretLogined
? "/open/dependencies"
: "/api/dependencies";
static get scriptDetail => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts/" : "/api/scripts/";
static get dependencyReinstall => getIt<UserInfoViewModel>().useSecretLogined
? "/open/dependencies/reinstall"
: "/api/dependencies/reinstall";
static get dependencies => getIt<UserInfoViewModel>().useSecretLogined ? "/open/dependencies" : "/api/dependencies";
static get addScript => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts" : "/api/scripts";
static get dependencyReinstall => getIt<UserInfoViewModel>().useSecretLogined ? "/open/dependencies/reinstall" : "/api/dependencies/reinstall";
static intimeLog(String cronId) {
return getIt<UserInfoViewModel>().useSecretLogined
? "/open/crons/$cronId/log"
: "/api/crons/$cronId/log";
return getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons/$cronId/log" : "/api/crons/$cronId/log";
}
static envMove(String envId) {
return getIt<UserInfoViewModel>().useSecretLogined
? "/open/envs/$envId/move"
: "/api/envs/$envId/move";
return getIt<UserInfoViewModel>().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;
@@ -138,7 +89,4 @@ class Url {
}
return false;
}
static String checkUpdateUrl =
"https://raw.githubusercontent.com/qinglong-app/qinglong_app/main/version";
}

View File

@@ -7,7 +7,6 @@ import 'package:qinglong_app/module/env/env_detail_page.dart';
import 'package:qinglong_app/module/home/home_page.dart';
import 'package:qinglong_app/module/login/login_page.dart';
import 'package:qinglong_app/module/others/about_page.dart';
import 'package:qinglong_app/module/others/change_account_page.dart';
import 'package:qinglong_app/module/others/dependencies/add_dependency_page.dart';
import 'package:qinglong_app/module/others/dependencies/dependency_page.dart';
import 'package:qinglong_app/module/others/login_log/login_log_page.dart';
@@ -42,7 +41,6 @@ class Routes {
static const String routeUpdatePassword = "/updatePassword";
static const String routeAbout = "/about";
static const String routeTheme = "/theme";
static const String routeChangeAccount = "/changeAccount";
static Route<dynamic>? generateRoute(RouteSettings settings) {
switch (settings.name) {
@@ -105,7 +103,8 @@ class Routes {
case routeTaskLogDetail:
return CupertinoPageRoute(
builder: (context) => TaskLogDetailPage(
title: settings.arguments as String,
title: (settings.arguments as Map)['title'],
path: (settings.arguments as Map)['path'],
),
);
case routeScriptDetail:
@@ -139,10 +138,6 @@ class Routes {
return CupertinoPageRoute(
builder: (context) => const ThemePage(),
);
case routeChangeAccount:
return CupertinoPageRoute(
builder: (context) => const ChangeAccountPage(),
);
case routeScriptUpdate:
return CupertinoPageRoute(
builder: (context) => ScriptEditPage(

View File

@@ -10,7 +10,7 @@ import 'package:qinglong_app/utils/sp_utils.dart';
var themeProvider = ChangeNotifierProvider((ref) => ThemeViewModel());
const commonColor = Color(0xFF299343);
Color commonColor = const Color(0xFF299343);
Color _primaryColor = commonColor;
class ThemeViewModel extends ChangeNotifier {
@@ -71,7 +71,10 @@ class ThemeViewModel extends ChangeNotifier {
),
scaffoldBackgroundColor: const Color(0xfff5f5f5),
inputDecorationTheme: InputDecorationTheme(
labelStyle: TextStyle(color: _primaryColor),
labelStyle: TextStyle(
color: _primaryColor,
fontSize: 14,
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: _primaryColor,
@@ -152,7 +155,10 @@ class ThemeViewModel extends ChangeNotifier {
),
),
inputDecorationTheme: InputDecorationTheme(
labelStyle: TextStyle(color: _primaryColor),
labelStyle: TextStyle(
color: _primaryColor,
fontSize: 14,
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: _primaryColor,
@@ -208,12 +214,15 @@ class ThemeViewModel extends ChangeNotifier {
abstract class ThemeColors {
Color settingBgColor();
Color settingBordorColor();
Color titleColor();
Color descColor();
Color tabBarColor();
Color pinColor();
Color buttonBgColor();
@@ -256,6 +265,11 @@ class LightThemeColors extends ThemeColors {
Color settingBordorColor() {
return Colors.white;
}
@override
Color tabBarColor() {
return const Color(0xffF7F7F7);
}
}
class DartThemeColors extends ThemeColors {
@@ -293,4 +307,9 @@ class DartThemeColors extends ThemeColors {
Color settingBordorColor() {
return Color(0xff333333);
}
@override
Color tabBarColor() {
return Colors.black;
}
}

View File

@@ -26,8 +26,7 @@ class UserInfoViewModel {
_useSecertLogined = SpUtil.getBool(spSecretLogined, defValue: false);
_host = SpUtil.getString(spHost, defValue: '');
List<dynamic>? tempList =
jsonDecode(SpUtil.getString(spLoginHistory, defValue: '[]'));
List<dynamic>? tempList = jsonDecode(SpUtil.getString(spLoginHistory, defValue: '[]'));
if (tempList != null && tempList.isNotEmpty) {
for (Map<String, dynamic> value in tempList) {
@@ -41,8 +40,7 @@ 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;
@@ -95,13 +93,11 @@ 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();
}
SpUtil.putString(spLoginHistory, jsonEncode(historyAccounts));
}
@@ -121,8 +117,7 @@ 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<String, dynamic> json) {
userName = json['userName'];

View File

@@ -26,6 +26,12 @@ void main() async {
await SpUtil.getInstance();
getIt.registerSingleton<UserInfoViewModel>(UserInfoViewModel());
await SystemChrome.setPreferredOrientations(
[
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
],
);
runApp(
ProviderScope(
overrides: [

View File

@@ -187,7 +187,7 @@ class _AddEnvPageState extends ConsumerState<AddEnvPage> {
envBean.remarks = _remarkController.text;
HttpResponse<NullResponse> response = await Api.addEnv(
_nameController.text, _valueController.text, _remarkController.text,
id: envBean.sId);
id: envBean.id,nId: envBean.nId,);
if (response.success) {
(envBean.sId == null) ? "新增成功" : "修改成功".toast();

View File

@@ -4,6 +4,8 @@ import 'package:json_conversion_annotation/json_conversion_annotation.dart';
class EnvBean {
String? value;
String? sId;
String? _id;
int? id;
int? created;
int? status;
String? timestamp;
@@ -12,8 +14,12 @@ class EnvBean {
EnvBean({this.value, this.sId, this.created, this.status, this.timestamp, this.name, this.remarks});
get nId => _id;
EnvBean.fromJson(Map<String, dynamic> json) {
value = json['value'];
id = json['id'];
_id = json['_id'];
sId = json.containsKey('_id') ? json['_id'].toString() : (json.containsKey('id') ? json['id'].toString() : "");
created = int.tryParse(json['created'].toString());
status = json['status'];

View File

@@ -23,6 +23,14 @@ class EnvPage extends StatefulWidget {
class _EnvPageState extends State<EnvPage> {
final TextEditingController _searchController = TextEditingController();
@override
void initState() {
super.initState();
_searchController.addListener(() {
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return BaseStateWidget<EnvViewModel>(
@@ -37,7 +45,7 @@ class _EnvPageState extends State<EnvPage> {
(value.remarks?.contains(_searchController.text) ?? false)) {
list.add(EnvItemCell(
value,
i + 1,
i,
ref,
key: ValueKey(value.sId),
));
@@ -51,26 +59,28 @@ class _EnvPageState extends State<EnvPage> {
onRefresh: () async {
return model.loadData(false);
},
child: ReorderableListView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
header: searchCell(ref),
onReorder: (int oldIndex, int newIndex) {
if (list.length != model.list.length) {
"请先清空搜索关键词".toast();
return;
}
setState(() {
//交换数据
if (newIndex > oldIndex) {
newIndex -= 1;
child: SlidableAutoCloseBehavior(
child: ReorderableListView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
header: searchCell(ref),
onReorder: (int oldIndex, int newIndex) {
if (list.length != model.list.length) {
"请先清空搜索关键词".toast();
return;
}
final EnvBean item = model.list.removeAt(oldIndex);
model.list.insert(newIndex, item);
model.update(item.sId ?? "", newIndex, oldIndex);
});
},
children: list,
setState(() {
//交换数据
if (newIndex > oldIndex) {
newIndex -= 1;
}
final EnvBean item = model.list.removeAt(oldIndex);
model.list.insert(newIndex, item);
model.update(item.sId ?? "", newIndex, oldIndex);
});
},
children: list,
),
),
);
},
@@ -133,185 +143,181 @@ class EnvItemCell extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.of(context).pushNamed(Routes.routeEnvDetail, arguments: bean);
},
child: ColoredBox(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: Slidable(
key: ValueKey(bean.sId),
endActionPane: ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.45,
return ColoredBox(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: Slidable(
key: ValueKey(bean.sId),
endActionPane: ActionPane(
motion: const StretchMotion(),
extentRatio: 0.5,
children: [
SlidableAction(
backgroundColor: const Color(0xff5D5E70),
onPressed: (_) {
Navigator.of(context).pushNamed(Routes.routeAddEnv, arguments: bean);
},
foregroundColor: Colors.white,
icon: CupertinoIcons.pencil_outline,
),
SlidableAction(
backgroundColor: const Color(0xffA356D6),
onPressed: (_) {
enableEnv(context);
},
foregroundColor: Colors.white,
icon: bean.status == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp,
),
SlidableAction(
backgroundColor: const Color(0xffEA4D3E),
onPressed: (_) {
delEnv(context, ref);
},
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
),
],
),
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SlidableAction(
backgroundColor: Colors.grey,
flex: 1,
onPressed: (_) {
Navigator.of(context).pushNamed(Routes.routeAddEnv, arguments: bean);
},
foregroundColor: Colors.white,
icon: CupertinoIcons.pencil_outline,
),
SlidableAction(
backgroundColor: Colors.orange,
flex: 1,
onPressed: (_) {
enableEnv();
},
foregroundColor: Colors.white,
icon: bean.status == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp,
),
SlidableAction(
backgroundColor: Colors.red,
flex: 1,
onPressed: (_) {
delEnv(context, ref);
},
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
),
],
),
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 8,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: Row(
children: [
Material(
color: Colors.transparent,
child: Text(
bean.name ?? "",
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 18,
Material(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: InkWell(
onTap: () {
Navigator.of(context).pushNamed(Routes.routeEnvDetail, arguments: bean);
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 8,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: Row(
children: [
bean.status == 1
? const Icon(
Icons.dnd_forwardslash,
size: 18,
color: Color(0xffEA4D3E),
)
: Container(
padding: const EdgeInsets.symmetric(
horizontal: 5,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: ref.watch(themeProvider).primaryColor, width: 1),
),
child: Text(
"${getIndexByIndex(context, index)}",
style: TextStyle(color: ref.watch(themeProvider).primaryColor, fontSize: 12),
),
),
const SizedBox(
width: 5,
),
Material(
color: Colors.transparent,
child: Text(
bean.name ?? "",
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 16,
),
),
),
),
],
),
),
const SizedBox(
width: 5,
),
Material(
color: Colors.transparent,
child: Text(
Utils.formatGMTTime(bean.timestamp ?? ""),
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Row(
children: [
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(
"$index",
style: TextStyle(color: ref.watch(themeProvider).primaryColor, fontSize: 12),
const SizedBox(
width: 5,
),
Expanded(
child: Visibility(
visible: bean.remarks != null && bean.remarks!.isNotEmpty,
child: Material(
color: Colors.transparent,
child: Text(
"(${bean.remarks})",
maxLines: 1,
style: TextStyle(
height: 1,
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
),
),
),
),
],
),
),
const SizedBox(
width: 5,
),
bean.status == 1
? const Icon(
Icons.dnd_forwardslash,
size: 12,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
width: 5,
width: 15,
),
Material(
color: Colors.transparent,
child: Text(
bean.remarks ?? "-",
Utils.formatGMTTime(bean.timestamp ?? ""),
maxLines: 1,
style: TextStyle(
height: 1,
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
),
),
const Spacer(),
],
),
),
const SizedBox(
height: 8,
),
Material(
color: Colors.transparent,
child: Text(
bean.value ?? "",
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
const SizedBox(
height: 15,
),
Material(
color: Colors.transparent,
child: Text(
bean.value ?? "",
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
),
),
),
],
],
),
),
),
const Divider(
height: 1,
indent: 15,
),
],
),
),
const Divider(
height: 1,
indent: 15,
),
],
),
),
),
);
}
void enableEnv() {
void enableEnv(BuildContext context) {
ref.read(envProvider).enableEnv(bean.sId!, bean.status!);
}
void delEnv(BuildContext context, WidgetRef ref) {
showCupertinoDialog(
useRootNavigator: false,
context: context,
builder: (context) => CupertinoAlertDialog(
title: const Text("确认删除"),
@@ -344,4 +350,17 @@ class EnvItemCell extends StatelessWidget {
),
);
}
int getIndexByIndex(BuildContext context, int index) {
var list = ref.watch(envProvider.notifier).list;
int result = 0;
for (int i = 0; i <= index; i++) {
if (list.length > index && list[i].status == 0) {
result++;
}
}
return result;
}
}

View File

@@ -8,11 +8,9 @@ import 'package:qinglong_app/base/ql_app_bar.dart';
import 'package:qinglong_app/base/routes.dart';
import 'package:qinglong_app/module/config/config_page.dart';
import 'package:qinglong_app/module/env/env_page.dart';
import 'package:qinglong_app/module/home/system_bean.dart';
import 'package:qinglong_app/module/others/other_page.dart';
import 'package:qinglong_app/module/task/task_page.dart';
import 'package:move_to_background/move_to_background.dart';
import 'package:qinglong_app/utils/update_utils.dart';
import 'dart:math' as math;
import '../../utils/utils.dart';
@@ -47,7 +45,6 @@ class _HomePageState extends ConsumerState<HomePage>
_title = titles[0].title;
super.initState();
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
update();
getSystemBean();
});
}
@@ -243,17 +240,6 @@ class _HomePageState extends ConsumerState<HomePage>
);
}
void update() async {
String? result = await UpdateUtils().checkUpdate();
if (result != null && result.isNotEmpty) {
UpdateDialog updateDialog = UpdateDialog(context,
title: "发现新版本", updateContent: "版本号:v$result", onUpdate: () {
UpdateUtils.launchURL(result);
});
updateDialog.show();
}
}
void isNewYearDuration() {
DateTime date = DateTime.now();
DateTime dateYear1 = DateTime(2022, 1, 29);

View File

@@ -1,3 +1,4 @@
/// @author NewTab
import 'package:json_conversion_annotation/json_conversion_annotation.dart';
@@ -11,6 +12,98 @@ class SystemBean {
version = json['version'];
}
//2.12.2 以及以上版本,日志从dirs换成了data
bool isUpperVersion2_12_2() {
try {
List<String>? version1 = version?.split("\.");
String f = version1?[0] ?? "2";
String s = version1?[1] ?? "10";
String t = version1?[2] ?? "0";
if (f.length == 1) {
f = "0$f";
}
if (s.length == 1) {
s = "0$s";
}
if (t.length == 1) {
t = "0$t";
}
String tempSum = "$f$s$t";
if ((int.tryParse(tempSum) ?? 1) >= 021202) {
return true;
}
return false;
} catch (e) {
return false;
}
}
//2.13.0 以及以上版本日志详情接口参数有变化
bool isUpperVersion2_13_0() {
try {
List<String>? version1 = version?.split("\.");
String f = version1?[0] ?? "2";
String s = version1?[1] ?? "10";
String t = version1?[2] ?? "0";
if (f.length == 1) {
f = "0$f";
}
if (s.length == 1) {
s = "0$s";
}
if (t.length == 1) {
t = "0$t";
}
String tempSum = "$f$s$t";
if ((int.tryParse(tempSum) ?? 1) >= 021300) {
return true;
}
return false;
} catch (e) {
return false;
}
}
// 2.10.13以上版本,针对任务,环境变量编辑做了修改
bool isUpperVersion() {
try {
List<String>? version1 = version?.split("\.");
String f = version1?[0] ?? "2";
String s = version1?[1] ?? "10";
String t = version1?[2] ?? "0";
if (f.length == 1) {
f = "0$f";
}
if (s.length == 1) {
s = "0$s";
}
if (t.length == 1) {
t = "0$t";
}
String tempSum = "$f$s$t";
if ((int.tryParse(tempSum) ?? 1) > 021013) {
return true;
}
return false;
} catch (e) {
return false;
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['version'] = this.version;
@@ -20,4 +113,4 @@ class SystemBean {
static SystemBean jsonConversion(Map<String, dynamic> json) {
return SystemBean.fromJson(json);
}
}
}

View File

@@ -3,16 +3,13 @@ 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';
import 'package:qinglong_app/base/routes.dart';
import 'package:qinglong_app/base/theme.dart';
import 'package:qinglong_app/base/userinfo_viewmodel.dart';
import 'package:qinglong_app/main.dart';
import 'package:qinglong_app/module/login/user_bean.dart';
import 'package:qinglong_app/utils/extension.dart';
import 'package:qinglong_app/utils/login_helper.dart';
import 'package:qinglong_app/utils/update_utils.dart';
import 'package:qinglong_app/utils/utils.dart';
import 'package:flip_card/flip_card.dart';
@@ -66,7 +63,6 @@ class _LoginPageState extends ConsumerState<LoginPage> {
}
getIt<UserInfoViewModel>().updateToken("");
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
update();
if (useSecretLogin) {
cardKey.currentState?.toggleCard();
}
@@ -129,15 +125,9 @@ class _LoginPageState extends ConsumerState<LoginPage> {
}
WidgetsBinding.instance?.endOfFrame;
},
child: ColorFiltered(
colorFilter: ColorFilter.mode(
ref.watch(themeProvider).primaryColor,
BlendMode.srcIn,
),
child: Image.asset(
"assets/images/ql.png",
height: 45,
),
child: Image.asset(
"assets/images/ql.png",
height: 45,
),
),
],
@@ -522,16 +512,6 @@ class _LoginPageState extends ConsumerState<LoginPage> {
});
}
void update() async {
String? result = await UpdateUtils().checkUpdate();
if (result != null && result.isNotEmpty) {
UpdateDialog updateDialog = UpdateDialog(context, title: "发现新版本", updateContent: "版本号:v${result}", onUpdate: () {
UpdateUtils.launchURL(result);
});
updateDialog.show();
}
}
Widget buildCell(UserInfoBean bean) {
return ListTile(
title: Text(

View File

@@ -3,7 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:qinglong_app/base/ql_app_bar.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:qinglong_app/base/theme.dart';
import 'package:qinglong_app/utils/update_utils.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../main.dart';
@@ -25,19 +24,6 @@ class _AboutPageState extends ConsumerState<AboutPage> {
super.initState();
getInfo();
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
update();
});
}
void update() async {
String? result = await UpdateUtils().checkUpdate(true);
if (result != null && result.isNotEmpty) {
UpdateDialog updateDialog = UpdateDialog(context, title: "发现新版本", updateContent: "版本号:v${result}", onUpdate: () {
UpdateUtils.launchURL(result);
});
updateDialog.show();
}
}
@override

View File

@@ -1,316 +0,0 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:qinglong_app/base/http/api.dart';
import 'package:qinglong_app/base/http/http.dart';
import 'package:qinglong_app/base/ql_app_bar.dart';
import 'package:qinglong_app/base/routes.dart';
import 'package:qinglong_app/base/theme.dart';
import 'package:qinglong_app/base/userinfo_viewmodel.dart';
import 'package:qinglong_app/utils/extension.dart';
import 'package:qinglong_app/utils/login_helper.dart';
import '../../main.dart';
class ChangeAccountPage extends ConsumerStatefulWidget {
const ChangeAccountPage({Key? key}) : super(key: key);
@override
_ChangeAccountPageState createState() => _ChangeAccountPageState();
}
class _ChangeAccountPageState extends ConsumerState<ChangeAccountPage> {
String isLoginingHost = "";
String preHost = "";
@override
void initState() {
super.initState();
preHost = getIt<UserInfoViewModel>().historyAccounts.first.host ?? "";
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: QlAppBar(
canBack: true,
title: "切换账号",
),
body: SingleChildScrollView(
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: MediaQuery.of(context).size.height / 10,
),
Text(
"轻触账号以切换登录",
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 22,
),
),
const SizedBox(
height: 30,
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15,
),
child: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
if (index == getIt<UserInfoViewModel>().historyAccounts.length) {
return addAccount();
}
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
color: ref.watch(themeProvider).themeColor.settingBordorColor(),
child: buildCell(index),
),
);
},
separatorBuilder: (_, __) {
return const SizedBox(
height: 10,
);
},
itemCount: getIt<UserInfoViewModel>().historyAccounts.length + 1),
),
],
),
),
),
);
}
Widget buildCell(int index) {
Widget child = ListTile(
title: Text(
getIt<UserInfoViewModel>().historyAccounts[index].host ?? "",
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 15,
),
minVerticalPadding: 10,
subtitle: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Text(
getIt<UserInfoViewModel>().historyAccounts[index].userName ?? "",
),
),
trailing: index == 0
? Container(
padding: const EdgeInsets.symmetric(
horizontal: 5,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: ref.watch(themeProvider).primaryColor, width: 1),
),
child: Text(
"已登录",
style: TextStyle(color: ref.watch(themeProvider).primaryColor, fontSize: 12),
),
)
: (isLoginingHost.isNotEmpty
? SizedBox(
width: 15,
height: 15,
child: CircularProgressIndicator(
strokeWidth: 2,
color: ref.watch(themeProvider).primaryColor,
),
)
: const SizedBox.shrink()),
);
if (getIt<UserInfoViewModel>().historyAccounts[index].host == getIt<UserInfoViewModel>().host) {
return child;
}
return Slidable(
key: ValueKey(index),
endActionPane: ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.15,
children: [
SlidableAction(
backgroundColor: Colors.red,
flex: 1,
onPressed: (_) {
getIt<UserInfoViewModel>().removeHistoryAccount(getIt<UserInfoViewModel>().historyAccounts[index].host);
setState(() {});
},
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
),
],
),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
loginNewByBean(getIt<UserInfoViewModel>().historyAccounts[index]);
},
child: child),
);
}
LoginHelper? helper;
void loginNewByBean(UserInfoBean historyAccount) async {
isLoginingHost = historyAccount.host ?? "";
setState(() {});
helper = LoginHelper(
historyAccount.useSecretLogined,
historyAccount.host ?? "",
historyAccount.userName ?? "",
historyAccount.password ?? "",
true,
);
var response = await helper!.login();
dealLoginResponse(response);
}
void dealLoginResponse(int response) {
if (response == LoginHelper.success) {
Navigator.of(context).pushNamedAndRemoveUntil(Routes.routeHomePage, (_) => false);
} else if (response == LoginHelper.failed) {
loginFailed();
} else {
twoFact();
}
}
void loginFailed() {
isLoginingHost = "";
Http.clear();
getIt<UserInfoViewModel>().updateHost(preHost);
setState(() {});
}
void twoFact() {
String twoFact = "";
showCupertinoDialog(
context: context,
builder: (_) => CupertinoAlertDialog(
title: const Text("两步验证"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Material(
color: Colors.transparent,
child: TextField(
onChanged: (value) {
twoFact = value;
},
maxLines: 1,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入code",
),
autofocus: true,
),
),
],
),
actions: [
CupertinoDialogAction(
child: const Text(
"取消",
style: TextStyle(
color: Color(0xff999999),
),
),
onPressed: () {
Navigator.of(context).pop();
},
),
CupertinoDialogAction(
child: Text(
"确定",
style: TextStyle(
color: ref.watch(themeProvider).primaryColor,
),
),
onPressed: () async {
Navigator.of(context).pop(true);
if (helper != null) {
var response = await helper!.loginTwice(twoFact);
dealLoginResponse(response);
} else {
"状态异常".toast();
}
},
),
],
)).then((value) {
if (value == null) {
isLoginingHost = "";
setState(() {});
}
});
}
Widget addAccount() {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pushNamedAndRemoveUntil(
Routes.routeLogin,
(_) => false,
arguments: true,
);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 15,
horizontal: 15,
),
decoration: BoxDecoration(
color: ref.watch(themeProvider).themeColor.settingBordorColor(),
borderRadius: BorderRadius.circular(15),
),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(
color: ref.watch(themeProvider).themeColor.descColor(),
),
),
child: Icon(
CupertinoIcons.add,
color: ref.watch(themeProvider).themeColor.descColor(),
),
),
const SizedBox(
width: 15,
),
Text(
"添加账号",
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 16,
),
),
],
),
),
),
);
}
}

View File

@@ -304,41 +304,6 @@ class _OtherPageState extends ConsumerState<OtherPage> {
const Divider(
indent: 15,
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pushNamed(Routes.routeChangeAccount);
},
child: Padding(
padding: const EdgeInsets.only(
left: 15,
right: 15,
top: 5,
bottom: 5,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"切换账号",
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 16,
),
),
const Spacer(),
const Icon(
CupertinoIcons.right_chevron,
size: 16,
),
],
),
),
),
const Divider(
indent: 15,
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {

View File

@@ -2,6 +2,11 @@ import 'package:code_text_field/code_text_field.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/http/api.dart';
import 'package:qinglong_app/base/http/http.dart';
import 'package:qinglong_app/base/ql_app_bar.dart';
@@ -41,11 +46,32 @@ class _ScriptEditPageState extends ConsumerState<ScriptEditPage> {
});
}
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;
}
@override
Widget build(BuildContext context) {
_codeController ??= CodeController(
text: widget.content,
language: javascript,
language: getLanguageType(widget.title),
onChange: (value) {
result = value;
},
@@ -91,10 +117,24 @@ class _ScriptEditPageState extends ConsumerState<ScriptEditPage> {
),
body: SafeArea(
top: false,
child: CodeField(
controller: _codeController!,
expands: true,
background: ref.watch(themeProvider).themeColor.settingBgColor(),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
child: CodeField(
controller: _codeController!,
expands: true,
wrap: true,
lineNumberStyle: LineNumberStyle(
width: 0,
margin: 0,
textStyle: TextStyle(
color: ref.watch(themeProvider).themeColor.descColor(),
),
),
background: ref.watch(themeProvider).themeColor.tabBarColor(),
),
),
),
);

View File

@@ -20,6 +20,18 @@ class ScriptPage extends ConsumerStatefulWidget {
class _ScriptPageState extends ConsumerState<ScriptPage> with LazyLoadState<ScriptPage> {
List<ScriptBean> list = [];
final TextEditingController _searchController = TextEditingController();
final TextEditingController _nameController = TextEditingController();
String? path;
@override
void initState() {
super.initState();
_searchController.addListener(() {
setState(() {});
});
}
@override
Widget build(BuildContext context) {
@@ -30,83 +42,167 @@ class _ScriptPageState extends ConsumerState<ScriptPage> with LazyLoadState<Scri
Navigator.of(context).pop();
},
title: "脚本管理",
actions: [
InkWell(
onTap: () {
addScript();
},
child: const Padding(
padding: EdgeInsets.symmetric(
horizontal: 15,
),
child: Center(
child: Icon(
CupertinoIcons.add,
size: 24,
color: Colors.white,
),
),
),
),
],
),
body: list.isEmpty
? const Center(
child: CupertinoActivityIndicator(),
)
child: CupertinoActivityIndicator(),
)
: ListView.builder(
itemBuilder: (context, index) {
ScriptBean item = list[index];
itemBuilder: (context, index) {
if (index == 0) {
return searchCell(ref);
}
return ColoredBox(
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!
.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();
}
});
},
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();
}
},
);
},
title: Text(
item.title ?? "",
style: TextStyle(
color:
(item.disabled ?? false) ? ref.watch(themeProvider).themeColor.descColor() : ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 16,
),
),
),
);
},
itemCount: list.length,
),
ScriptBean item = list[index - 1];
if (_searchController.text.isEmpty ||
(item.title?.contains(_searchController.text) ?? false) ||
(item.value?.contains(_searchController.text) ?? false) ||
((item.children?.where((e) {
return (e.title?.contains(_searchController.text) ?? false) || (e.value?.contains(_searchController.text) ?? false);
}).isNotEmpty ??
false))) {
return ColoredBox(
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();
}
});
},
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();
}
},
);
},
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();
}
},
itemCount: list.length + 1,
),
);
}
Widget searchCell(WidgetRef context) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 10,
),
child: CupertinoSearchTextField(
onSubmitted: (value) {
setState(() {});
},
onSuffixTap: () {
_searchController.text = "";
setState(() {});
},
controller: _searchController,
borderRadius: BorderRadius.circular(
30,
),
padding: const EdgeInsets.symmetric(
horizontal: 5,
vertical: 5,
),
suffixInsets: const EdgeInsets.only(
right: 15,
),
prefixInsets: const EdgeInsets.only(
top: 6,
bottom: 6,
left: 15,
),
placeholderStyle: TextStyle(
fontSize: 16,
color: context.watch(themeProvider).themeColor.descColor(),
),
style: const TextStyle(
fontSize: 16,
),
placeholder: "搜索",
),
);
}
@@ -129,4 +225,139 @@ class _ScriptPageState extends ConsumerState<ScriptPage> with LazyLoadState<Scri
void onLazyLoad() {
loadData();
}
String scriptPath = "";
void addScript() {
showCupertinoDialog(
useRootNavigator: false,
context: context,
builder: (context) => 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: TextField(
controller: _nameController,
decoration: const InputDecoration(
isDense: true,
contentPadding: EdgeInsets.all(4),
hintText: "请输入脚本名称",
hintStyle: TextStyle(
fontSize: 14,
),
),
autofocus: false,
),
),
const SizedBox(
height: 10,
),
const Text(
"脚本所属文件夹:",
style: TextStyle(
fontSize: 14,
),
),
const SizedBox(
height: 10,
),
DropdownButtonFormField<String>(
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<NullResponse> 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();
}
},
),
],
),
);
}
}

View File

@@ -6,20 +6,30 @@ class TaskLogBean {
String? name;
bool? isDir;
List<String>? files;
List<Children>? children;
TaskLogBean({this.name, this.isDir, this.files});
TaskLogBean({this.name, this.files});
TaskLogBean.fromJson(Map<String, dynamic> json) {
name = json['name'];
isDir = json['isDir'];
files = json['files'].cast<String>();
name = json['name'] ?? json['title'];
isDir = json['isDir'] ?? (json['type'] == "directory");
files = json['files']?.cast<String>();
if (json['children'] != null) {
children = <Children>[];
json['children'].forEach((v) {
children!.add(Children.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['isDir'] = this.isDir;
data['files'] = this.files;
if (this.children != null) {
data['children'] = this.children!.map((v) => v.toJson()).toList();
}
return data;
}
@@ -27,3 +37,31 @@ class TaskLogBean {
return TaskLogBean.fromJson(json);
}
}
class Children {
String? title;
String? value;
String? type;
String? key;
String? parent;
Children({this.title, this.value, this.type, this.key, this.parent});
Children.fromJson(Map<String, dynamic> json) {
title = json['title'];
value = json['value'];
type = json['type'];
key = json['key'];
parent = json['parent'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['title'] = this.title;
data['value'] = this.value;
data['type'] = this.type;
data['key'] = this.key;
data['parent'] = this.parent;
return data;
}
}

View File

@@ -12,10 +12,12 @@ import 'package:qinglong_app/utils/extension.dart';
/// @author NewTab
class TaskLogDetailPage extends ConsumerStatefulWidget {
final String title;
final String path;
const TaskLogDetailPage({
Key? key,
required this.title,
required this.path,
}) : super(key: key);
@override
@@ -38,21 +40,22 @@ class _TaskLogDetailPageState extends ConsumerState<TaskLogDetailPage> 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,
),
),
);
}
Future<void> loadData() async {
HttpResponse<String> response = await Api.taskLogDetail(
widget.title,
widget.path,
);
if (response.success) {

View File

@@ -43,40 +43,66 @@ class _TaskLogPageState extends ConsumerState<TaskLogPage> with LazyLoadState<Ta
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: (item.isDir ?? false)
? ExpansionTile(
title: Text(
item.name ?? "",
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 16,
),
),
children: item.files!
.map((e) => ListTile(
onTap: () {
Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: item.name! + "/" + e);
},
title: Text(
e,
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 14,
),
),
))
.toList(),
)
: ListTile(
onTap: () {
Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: item.name);
},
title: Text(
item.name ?? "",
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 16,
),
),
title: Text(
item.name ?? "",
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 16,
),
),
children: (item.files?.isNotEmpty ?? false)
? item.files!
.map((e) => ListTile(
onTap: () {
Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: {
"path": item.name,
"title": e,
});
},
title: Text(
e,
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 14,
),
),
))
.toList()
: (item.children ?? [])
.map((e) => ListTile(
onTap: () {
Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: {
"path": item.name,
"title": e.title,
});
},
title: Text(
e.title ?? "",
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 14,
),
),
))
.toList(),
)
: ListTile(
onTap: () {
if (item.isDir ?? false) {
"该文件夹为空".toast();
return;
}
Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: item.name);
},
title: Text(
item.name ?? "",
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 16,
),
),
),
);
},
itemCount: list.length,

View File

@@ -74,111 +74,113 @@ class _AddTaskPageState extends ConsumerState<AddTaskPage> {
)
],
),
body: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15,
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: 15,
),
const Text(
"名称:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
focusNode: focusNode,
controller: _nameController,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入名称",
),
autofocus: false,
),
],
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 15,
),
const Text(
"名称:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 15,
),
),
TextField(
focusNode: focusNode,
controller: _nameController,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入名称",
const Text(
"命令:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
autofocus: false,
),
],
TextField(
controller: _commandController,
maxLines: 4,
minLines: 1,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入命令",
),
autofocus: false,
),
],
),
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15,
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 15,
),
const Text(
"定时:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
controller: _cronController,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入定时",
),
autofocus: false,
),
const SizedBox(
height: 5,
),
const Text(
"定时的cron不校验是否正确",
style: TextStyle(
fontSize: 12,
),
),
],
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 15,
),
const Text(
"命令:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
controller: _commandController,
maxLines: 4,
minLines: 1,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入命令",
),
autofocus: false,
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 15,
),
const Text(
"定时:",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
TextField(
controller: _cronController,
decoration: const InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
hintText: "请输入定时",
),
autofocus: false,
),
const SizedBox(
height: 5,
),
const Text(
"定时的cron不校验是否正确",
style: TextStyle(
fontSize: 12,
),
),
],
),
),
],
],
),
),
);
}
@@ -206,7 +208,7 @@ class _AddTaskPageState extends ConsumerState<AddTaskPage> {
taskBean.schedule = _cronController.text;
HttpResponse<NullResponse> response = await Api.addTask(
_nameController.text, _commandController.text, _cronController.text,
id: taskBean.sId);
id: taskBean.id,);
if (response.success) {
(widget.taskBean?.sId == null) ? "新增成功" : "修改成功".toast();

View File

@@ -11,6 +11,8 @@ class TaskBean {
String? schedule;
bool? saved;
String? sId;
int? id;
String? _id;
int? created;
int? status;
String? timestamp;
@@ -24,20 +26,22 @@ 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;
TaskBean.fromJson(Map<String, dynamic> json) {
try {
@@ -45,6 +49,8 @@ class TaskBean {
command = json['command'].toString();
schedule = json['schedule'].toString();
saved = json['saved'];
id = json['id'];
_id = json['_id'];
sId = json.containsKey('_id') ? json['_id'].toString() : (json.containsKey('id') ? json['id'].toString() : "");
created = int.tryParse(json['created'].toString());
status = json['status'];

View File

@@ -3,91 +3,41 @@ import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:qinglong_app/base/base_state_widget.dart';
import 'package:qinglong_app/base/routes.dart';
import 'package:qinglong_app/base/theme.dart';
import 'package:qinglong_app/base/ui/abs_underline_tabindicator.dart';
import 'package:qinglong_app/base/ui/empty_widget.dart';
import 'package:qinglong_app/base/ui/menu.dart';
import 'package:qinglong_app/base/ui/ql_context_menu.dart';
import 'package:qinglong_app/module/task/intime_log/intime_log_page.dart';
import 'package:qinglong_app/module/task/task_bean.dart';
import 'package:qinglong_app/module/task/task_detail/task_detail_page.dart';
import 'package:qinglong_app/module/task/task_viewmodel.dart';
import 'package:qinglong_app/utils/utils.dart';
class TaskPage extends StatefulWidget {
class TaskPage extends ConsumerStatefulWidget {
const TaskPage({Key? key}) : super(key: key);
@override
_TaskPageState createState() => _TaskPageState();
}
class _TaskPageState extends State<TaskPage> {
class _TaskPageState extends ConsumerState<TaskPage> {
final TextEditingController _searchController = TextEditingController();
String currentState = TaskViewModel.allStr;
@override
void initState() {
super.initState();
_searchController.addListener(() {
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return BaseStateWidget<TaskViewModel>(
builder: (ref, model, child) {
return Column(
mainAxisSize: MainAxisSize.max,
children: [
searchCell(ref),
Expanded(
child: DefaultTabController(
length: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TabBar(
tabs: const [
Tab(
text: "全部",
),
Tab(
text: "正在运行",
),
Tab(
text: "从未运行",
),
Tab(
text: "拉库脚本",
),
Tab(
text: "已禁用",
),
],
isScrollable: true,
indicator: AbsUnderlineTabIndicator(
wantWidth: 20,
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 2,
)),
),
Expanded(
child: TabBarView(
children: [
body(model, model.list, ref),
body(model, model.running, ref),
body(model, model.neverRunning, ref),
body(model, model.notScripts, ref),
body(model, model.disabled, ref),
],
),
),
],
),
),
),
],
);
return body(model, getListByType(model), ref);
},
model: taskProvider,
onReady: (viewModel) {
@@ -100,26 +50,51 @@ class _TaskPageState extends State<TaskPage> {
return RefreshIndicator(
color: Theme.of(context).primaryColor,
onRefresh: () async {
return model.loadData(false);
return model.loadData( false);
},
child: list.isEmpty
? const EmptyWidget()
: ListView.builder(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
itemBuilder: (context, index) {
TaskBean item = list[index];
if (_searchController.text.isEmpty ||
(item.name?.toLowerCase().contains(_searchController.text.toLowerCase()) ?? false) ||
(item.command?.toLowerCase().contains(_searchController.text.toLowerCase()) ?? false) ||
(item.schedule?.contains(_searchController.text.toLowerCase()) ?? false)) {
return TaskItemCell(item, ref);
} else {
return const SizedBox.shrink();
}
},
itemCount: list.length,
),
child: IconTheme(
data: const IconThemeData(
size: 25,
),
child: SlidableAutoCloseBehavior(
child: ListView.separated(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
itemBuilder: (context, index) {
if (index == 0) {
return searchCell(ref);
}
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)) {
return TaskItemCell(item, ref);
} else {
return const SizedBox.shrink();
}
},
itemCount: list.length + 1,
separatorBuilder: (BuildContext context, int index) {
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)) {
return Container(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: const Divider(
height: 1,
indent: 15,
),
);
} else {
return const SizedBox.shrink();
}
},
),
),
),
);
}
@@ -129,41 +104,149 @@ class _TaskPageState extends State<TaskPage> {
horizontal: 15,
vertical: 10,
),
child: CupertinoSearchTextField(
onSubmitted: (value) {
setState(() {});
},
onSuffixTap: () {
_searchController.text = "";
setState(() {});
},
controller: _searchController,
borderRadius: BorderRadius.circular(
30,
),
padding: const EdgeInsets.symmetric(
horizontal: 5,
vertical: 5,
),
suffixInsets: const EdgeInsets.only(
right: 15,
),
prefixInsets: EdgeInsets.only(
top: Platform.isAndroid ? 10 : 6,
bottom: 6,
left: 15,
),
placeholderStyle: TextStyle(
fontSize: 16,
color: context.watch(themeProvider).themeColor.descColor(),
),
style: const TextStyle(
fontSize: 16,
),
placeholder: "搜索",
child: Row(
children: [
Expanded(
child: CupertinoSearchTextField(
onSubmitted: (value) {
setState(() {});
},
onSuffixTap: () {
_searchController.text = "";
setState(() {});
},
controller: _searchController,
borderRadius: BorderRadius.circular(
30,
),
padding: const EdgeInsets.symmetric(
horizontal: 5,
vertical: 5,
),
suffixInsets: const EdgeInsets.only(
right: 15,
),
prefixInsets: EdgeInsets.only(
top: Platform.isAndroid ? 10 : 6,
bottom: 6,
left: 15,
),
placeholderStyle: TextStyle(
fontSize: 16,
color: context.watch(themeProvider).themeColor.descColor(),
),
style: const TextStyle(
fontSize: 16,
),
placeholder: "搜索",
),
),
Material(
color: Colors.transparent,
child: PopupMenuButton<String>(
onSelected: (String result) {
currentState = result;
setState(() {});
},
itemBuilder: (BuildContext context) => [
PopupMenuItem(
child: Text(
TaskViewModel.allStr,
style: TextStyle(
color: currentState == TaskViewModel.allStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 14,
),
),
value: TaskViewModel.allStr,
),
PopupMenuItem(
child: Text(
TaskViewModel.runningStr,
style: TextStyle(
color:
currentState == TaskViewModel.runningStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 14,
),
),
value: TaskViewModel.runningStr,
),
PopupMenuItem(
child: Text(
TaskViewModel.neverStr,
style: TextStyle(
color: currentState == TaskViewModel.neverStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 14,
),
),
value: TaskViewModel.neverStr,
),
PopupMenuItem(
child: Row(
children: [
Text(
TaskViewModel.notScriptStr,
style: TextStyle(
color: currentState == TaskViewModel.notScriptStr
? ref.watch(themeProvider).primaryColor
: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 14,
),
),
],
),
value: TaskViewModel.notScriptStr,
),
PopupMenuItem(
child: Text(
TaskViewModel.disableStr,
style: TextStyle(
fontSize: 14,
color:
currentState == TaskViewModel.disableStr ? ref.watch(themeProvider).primaryColor : ref.watch(themeProvider).themeColor.titleColor(),
),
),
value: TaskViewModel.disableStr,
),
],
child: Padding(
padding: const EdgeInsets.only(
left: 10,
),
child: Text(
"筛选",
style: TextStyle(
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 14,
),
),
),
),
),
],
),
);
}
List<TaskBean> getListByType(TaskViewModel model) {
if (currentState == TaskViewModel.allStr) {
return model.list;
}
if (currentState == TaskViewModel.runningStr) {
return model.running;
}
if (currentState == TaskViewModel.neverStr) {
return model.neverRunning;
}
if (currentState == TaskViewModel.notScriptStr) {
return model.notScripts;
}
if (currentState == TaskViewModel.disableStr) {
return model.disabled;
}
return model.list;
}
}
class TaskItemCell extends StatelessWidget {
@@ -176,93 +259,91 @@ class TaskItemCell extends StatelessWidget {
Widget build(BuildContext context) {
return ColoredBox(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: QlCupertinoContextMenu(
bean: bean,
actions: [
QLCupertinoContextMenuAction(
child: Text(
bean.status! == 1 ? "运行" : "停止运行",
),
trailingIcon: bean.status! == 1 ? CupertinoIcons.memories : CupertinoIcons.stop_circle,
onPressed: () {
Navigator.of(context).pop();
if (bean.status! == 1) {
startCron(context, ref);
} else {
stopCron(context, ref);
}
},
),
QLCupertinoContextMenuAction(
child: const Text("查看日志"),
onPressed: () {
Navigator.of(context).pop();
logCron(context, ref);
},
trailingIcon: CupertinoIcons.clock,
),
QLCupertinoContextMenuAction(
child: const Text("编辑"),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(Routes.routeAddTask, arguments: bean);
},
trailingIcon: CupertinoIcons.pencil_outline,
),
QLCupertinoContextMenuAction(
child: Text(bean.isPinned! == 0 ? "置顶" : "取消置顶"),
onPressed: () {
Navigator.of(context).pop();
pinTask();
},
trailingIcon: bean.isPinned! == 0 ? CupertinoIcons.pin : CupertinoIcons.pin_slash,
),
QLCupertinoContextMenuAction(
child: Text(bean.isDisabled! == 0 ? "禁用" : "启用"),
onPressed: () {
Navigator.of(context).pop();
enableTask();
},
isDestructiveAction: true,
trailingIcon: bean.isDisabled! == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp,
),
QLCupertinoContextMenuAction(
child: const Text("删除"),
onPressed: () {
Navigator.of(context).pop();
delTask(context, ref);
},
isDestructiveAction: true,
trailingIcon: CupertinoIcons.delete,
),
],
previewBuilder: (context, anima, child) {
bool isDark = ref.watch(themeProvider).darkMode;
return ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Container(
color: isDark ? const Color(0xff333333) : Theme.of(context).scaffoldBackgroundColor,
padding: EdgeInsets.only(
left: 5,
right: 5,
top: 5,
bottom: isDark ? 5 : 20,
),
child: SizedBox(
height: 200,
child: TaskDetailPage(
bean,
hideAppbar: true,
),
),
),
);
},
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
child: Slidable(
key: ValueKey(bean.sId),
endActionPane: ActionPane(
motion: const StretchMotion(),
extentRatio: 0.7,
children: [
Container(
SlidableAction(
backgroundColor: const Color(0xff5D5E70),
onPressed: (_) {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
Navigator.of(context).pushNamed(Routes.routeAddTask, arguments: bean);
});
},
foregroundColor: Colors.white,
icon: CupertinoIcons.pencil_outline,
),
SlidableAction(
backgroundColor: const Color(0xffF19A39),
onPressed: (_) {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
pinTask(context);
});
},
foregroundColor: Colors.white,
icon: bean.isPinned! == 0 ? CupertinoIcons.pin : CupertinoIcons.pin_slash,
),
SlidableAction(
backgroundColor: const Color(0xffA356D6),
onPressed: (_) {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
enableTask(context);
});
},
foregroundColor: Colors.white,
icon: bean.isDisabled! == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp,
),
SlidableAction(
backgroundColor: const Color(0xffEA4D3E),
onPressed: (_) {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
delTask(context, ref);
});
},
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
),
],
),
startActionPane: ActionPane(
motion: const StretchMotion(),
extentRatio: 0.4,
children: [
SlidableAction(
backgroundColor: const Color(0xffD25535),
onPressed: (_) {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
if (bean.status! == 1) {
startCron(context, ref);
} else {
stopCron(context, ref);
}
});
},
foregroundColor: Colors.white,
icon: bean.status! == 1 ? CupertinoIcons.memories : CupertinoIcons.stop_circle,
),
SlidableAction(
backgroundColor: const Color(0xff606467),
onPressed: (_) {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
logCron(context, ref);
});
},
foregroundColor: Colors.white,
icon: CupertinoIcons.text_justifyleft,
),
],
),
child: Material(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: InkWell(
onTap: () {
Navigator.of(context).pushNamed(Routes.routeTaskDetail, arguments: bean);
},
child: Container(
width: MediaQuery.of(context).size.width,
color: bean.isPinned == 1 ? ref.watch(themeProvider).themeColor.pinColor() : Colors.transparent,
padding: const EdgeInsets.symmetric(
@@ -282,11 +363,21 @@ class TaskItemCell extends StatelessWidget {
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: [
bean.isDisabled == 1
? const Icon(
Icons.dnd_forwardslash,
size: 18,
color: Color(0xffEA4D3E),
)
: const SizedBox.shrink(),
SizedBox(
width: bean.isDisabled == 1 ? 5 : 0,
),
bean.status == 1
? const SizedBox.shrink()
: SizedBox(
width: 15,
height: 15,
width: 13,
height: 13,
child: CircularProgressIndicator(
strokeWidth: 2,
color: ref.watch(themeProvider).primaryColor,
@@ -305,7 +396,7 @@ class TaskItemCell extends StatelessWidget {
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 18,
fontSize: 16,
),
),
),
@@ -328,37 +419,22 @@ class TaskItemCell extends StatelessWidget {
],
),
const SizedBox(
height: 8,
height: 5,
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
bean.isDisabled == 1
? const Icon(
Icons.dnd_forwardslash,
size: 12,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
width: 5,
Material(
color: Colors.transparent,
child: Text(
bean.schedule ?? "",
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
Material(
color: Colors.transparent,
child: Text(
bean.schedule ?? "",
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
),
),
],
),
),
const SizedBox(
height: 8,
height: 5,
),
Material(
color: Colors.transparent,
@@ -376,30 +452,27 @@ class TaskItemCell extends StatelessWidget {
],
),
),
const Divider(
height: 1,
indent: 15,
),
],
),
),
),
);
}
startCron(BuildContext context, WidgetRef ref) async {
await ref.read(taskProvider).runCrons(bean.sId!);
await ref.read(taskProvider).runCrons( bean.sId!);
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
logCron(context, ref);
});
}
stopCron(BuildContext context, WidgetRef ref) {
ref.read(taskProvider).stopCrons(bean.sId!);
ref.read(taskProvider).stopCrons( bean.sId!);
}
logCron(BuildContext context, WidgetRef ref) {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
showCupertinoDialog(
useRootNavigator: false,
builder: (BuildContext context) {
return CupertinoAlertDialog(
title: Text(
@@ -416,7 +489,7 @@ class TaskItemCell extends StatelessWidget {
),
onPressed: () {
Navigator.of(context).pop();
ref.read(taskProvider).loadData(false);
ref.read(taskProvider).loadData( false);
},
),
],
@@ -426,17 +499,18 @@ class TaskItemCell extends StatelessWidget {
});
}
void enableTask() {
ref.read(taskProvider).enableTask(bean.sId!, bean.isDisabled!);
void enableTask(BuildContext context) {
ref.read(taskProvider).enableTask( bean.sId!, bean.isDisabled!);
}
void pinTask() {
ref.read(taskProvider).pinTask(bean.sId!, bean.isPinned!);
void pinTask(BuildContext context) {
ref.read(taskProvider).pinTask( bean.sId!, bean.isPinned!);
}
void delTask(BuildContext context, WidgetRef ref) {
showCupertinoDialog(
context: context,
useRootNavigator: false,
builder: (context) => CupertinoAlertDialog(
title: const Text("确认删除"),
content: Text("确认删除定时任务 ${bean.name ?? ""}"),
@@ -461,7 +535,7 @@ class TaskItemCell extends StatelessWidget {
),
onPressed: () {
Navigator.of(context).pop();
ref.read(taskProvider).delCron(bean.sId!);
ref.watch(taskProvider.notifier).delCron(bean.sId!);
},
),
],

View File

@@ -8,6 +8,11 @@ import 'package:qinglong_app/utils/extension.dart';
var taskProvider = ChangeNotifierProvider((ref) => TaskViewModel());
class TaskViewModel extends BaseViewModel {
static const String allStr = "全部脚本";
static const String runningStr = "正在运行";
static const String neverStr = "从未运行";
static const String notScriptStr = "拉库脚本";
static const String disableStr = "禁用脚本";
List<TaskBean> list = [];
List<TaskBean> running = [];
List<TaskBean> neverRunning = [];
@@ -33,17 +38,85 @@ class TaskViewModel extends BaseViewModel {
}
void sortList() {
List<TaskBean> p = [];
List<TaskBean> r = [];
List<TaskBean> d = [];
for (int i = 0; i < list.length; i++) {
if (list[i].isPinned == 1) {
final TaskBean item = list.removeAt(i);
list.insert(0, item);
p.add(list.removeAt(i));
i--;
continue;
}
if (list[i].status == 0) {
r.add(list.removeAt(i));
i--;
continue;
}
if (list[i].isDisabled == 1) {
d.add(list.removeAt(i));
i--;
continue;
}
}
p.sort((TaskBean a, TaskBean b) {
bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0).isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0));
if (c == true) {
return 1;
}
return -1;
});
p.sort((a, b) {
return (a.isDisabled ?? 0) - (b.isDisabled ?? 0);
});
p.sort((a, b) {
if (a.status == 0 && b.status == 0) {
bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0).isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0));
if (c == true) {
return 1;
}
return -1;
} else {
return (a.status ?? 0) - (b.status ?? 0);
}
});
r.sort((a, b) {
bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0).isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0));
if (c == true) {
return 1;
}
return -1;
});
d.sort((a, b) {
bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0).isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0));
if (c == true) {
return 1;
}
return -1;
});
list.sort((a, b) {
bool c = DateTime.fromMillisecondsSinceEpoch(a.created ?? 0).isBefore(DateTime.fromMillisecondsSinceEpoch(b.created ?? 0));
if (c == true) {
return 1;
}
return -1;
});
list.insertAll(0, r);
list.insertAll(0, p);
list.addAll(d);
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")))));
disabled.clear();
@@ -53,9 +126,7 @@ class TaskViewModel extends BaseViewModel {
Future<void> runCrons(String cron) async {
HttpResponse<NullResponse> result = await Api.startTasks([cron]);
if (result.success) {
list.firstWhere((element) => element.sId == cron).status = 0;
sortList();
notifyListeners();
loadData(false);
} else {
failToast(result.message, notify: true);
}
@@ -64,9 +135,7 @@ class TaskViewModel extends BaseViewModel {
Future<void> stopCrons(String cron) async {
HttpResponse<NullResponse> result = await Api.stopTasks([cron]);
if (result.success) {
list.firstWhere((element) => element.sId == cron).status = 1;
sortList();
notifyListeners();
loadData(false);
} else {
failToast(result.message, notify: true);
}
@@ -75,9 +144,8 @@ class TaskViewModel extends BaseViewModel {
Future<void> delCron(String id) async {
HttpResponse<NullResponse> result = await Api.delTask(id);
if (result.success) {
list.removeWhere((element) => element.sId == id);
"删除成功".toast();
notifyListeners();
loadData(false);
} else {
failToast(result.message, notify: true);
}
@@ -101,9 +169,7 @@ class TaskViewModel extends BaseViewModel {
if (response.success) {
"取消置顶成功".toast();
list.firstWhere((element) => element.sId == sId).isPinned = 0;
sortList();
success();
loadData(false);
} else {
failToast(response.message, notify: true);
}
@@ -112,9 +178,7 @@ class TaskViewModel extends BaseViewModel {
if (response.success) {
"置顶成功".toast();
list.firstWhere((element) => element.sId == sId).isPinned = 1;
sortList();
success();
loadData(false);
} else {
failToast(response.message, notify: true);
}
@@ -127,9 +191,7 @@ class TaskViewModel extends BaseViewModel {
if (response.success) {
"禁用成功".toast();
list.firstWhere((element) => element.sId == sId).isDisabled = 1;
sortList();
success();
loadData(false);
} else {
failToast(response.message, notify: true);
}
@@ -138,9 +200,7 @@ class TaskViewModel extends BaseViewModel {
if (response.success) {
"启用成功".toast();
list.firstWhere((element) => element.sId == sId).isDisabled = 0;
sortList();
success();
loadData(false);
} else {
failToast(response.message, notify: true);
}

View File

@@ -1,399 +0,0 @@
import 'dart:io';
import 'dart:math';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:qinglong_app/base/http/url.dart';
import 'package:qinglong_app/utils/extension.dart';
import 'package:url_launcher/url_launcher.dart';
import '../main.dart';
/// @author NewTab
class UpdateUtils {
Future<String?> checkUpdate([bool remind = false]) async {
try {
if (!Platform.isAndroid) {
return null;
}
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String version = packageInfo.version;
String url = Url.checkUpdateUrl;
Dio dio = Dio(BaseOptions(
connectTimeout: 50000,
receiveTimeout: 50000,
sendTimeout: 50000,
));
var response = await dio.get(url);
if (response.statusCode == 200) {
if (version == response.data as String) {
return null;
}
return response.data as String;
}
} on DioError catch (e) {
if (remind) {
"无法连接到github服务器,版本更新检测失败".toast();
}
logger.e(e);
return null;
}
}
static void launchURL(String version) async {
try {
await launch("https://github.com/qinglong-app/qinglong_app/releases/download/v$version/app-release-v$version.apk");
} catch (e) {
logger.e(e);
}
}
}
///版本更新加提示框
class UpdateDialog {
bool _isShowing = false;
late BuildContext _context;
late UpdateWidget _widget;
UpdateDialog(BuildContext context,
{double width = 0.0,
required String title,
required String updateContent,
required VoidCallback onUpdate,
double titleTextSize = 16.0,
double contentTextSize = 14.0,
double buttonTextSize = 14.0,
double progress = -1.0,
Color progressBackgroundColor = const Color(0xFFFFCDD2),
Image? topImage,
double extraHeight = 5.0,
double radius = 4.0,
Color themeColor = Colors.red,
bool enableIgnore = false,
VoidCallback? onIgnore,
bool isForce = false,
String? updateButtonText,
String? ignoreButtonText,
VoidCallback? onClose}) {
_context = context;
_widget = UpdateWidget(
width: width,
title: title,
updateContent: updateContent,
onUpdate: onUpdate,
titleTextSize: titleTextSize,
contentTextSize: contentTextSize,
buttonTextSize: buttonTextSize,
progress: progress,
topImage: topImage,
extraHeight: extraHeight,
radius: radius,
themeColor: themeColor,
progressBackgroundColor: progressBackgroundColor,
enableIgnore: enableIgnore,
onIgnore: onIgnore,
isForce: isForce,
updateButtonText: updateButtonText ?? '更新',
ignoreButtonText: ignoreButtonText ?? '忽略此版本',
onClose: onClose ?? () => dismiss());
}
/// 显示弹窗
Future<bool> show() {
try {
if (isShowing()) {
return Future<bool>.value(false);
}
showDialog<bool>(
context: _context,
barrierDismissible: false,
builder: (BuildContext context) {
return WillPopScope(onWillPop: () => Future<bool>.value(false), child: _widget);
});
_isShowing = true;
return Future<bool>.value(true);
} catch (err) {
_isShowing = false;
return Future<bool>.value(false);
}
}
/// 隐藏弹窗
Future<bool> dismiss() {
try {
if (_isShowing) {
_isShowing = false;
Navigator.pop(_context);
return Future<bool>.value(true);
} else {
return Future<bool>.value(false);
}
} catch (err) {
return Future<bool>.value(false);
}
}
/// 是否显示
bool isShowing() {
return _isShowing;
}
/// 更新进度
void update(double progress) {
if (isShowing()) {
_widget.update(progress);
}
}
/// 显示版本更新提示框
static UpdateDialog showUpdate(BuildContext context,
{double width = 0.0,
required String title,
required String updateContent,
required VoidCallback onUpdate,
double titleTextSize = 16.0,
double contentTextSize = 14.0,
double buttonTextSize = 14.0,
double progress = -1.0,
Color progressBackgroundColor = const Color(0xFFFFCDD2),
Image? topImage,
double extraHeight = 5.0,
double radius = 4.0,
Color themeColor = Colors.red,
bool enableIgnore = false,
VoidCallback? onIgnore,
String? updateButtonText,
String? ignoreButtonText,
bool isForce = false}) {
final UpdateDialog dialog = UpdateDialog(context,
width: width,
title: title,
updateContent: updateContent,
onUpdate: onUpdate,
titleTextSize: titleTextSize,
contentTextSize: contentTextSize,
buttonTextSize: buttonTextSize,
progress: progress,
topImage: topImage,
extraHeight: extraHeight,
radius: radius,
themeColor: themeColor,
progressBackgroundColor: progressBackgroundColor,
enableIgnore: enableIgnore,
isForce: isForce,
updateButtonText: updateButtonText,
ignoreButtonText: ignoreButtonText,
onIgnore: onIgnore);
dialog.show();
return dialog;
}
}
// ignore: must_be_immutable
class UpdateWidget extends StatefulWidget {
/// 对话框的宽度
final double width;
/// 升级标题
final String title;
/// 更新内容
final String updateContent;
/// 标题文字的大小
final double titleTextSize;
/// 更新文字内容的大小
final double contentTextSize;
/// 按钮文字的大小
final double buttonTextSize;
/// 顶部图片
final Widget? topImage;
/// 拓展高度(适配顶部图片高度不一致的情况)
final double extraHeight;
/// 边框圆角大小
final double radius;
/// 主题颜色
final Color themeColor;
/// 更新事件
final VoidCallback onUpdate;
/// 可忽略更新
final bool enableIgnore;
/// 更新事件
final VoidCallback? onIgnore;
double progress;
/// 进度条的背景颜色
final Color progressBackgroundColor;
/// 更新事件
final VoidCallback? onClose;
/// 是否是强制更新
final bool isForce;
/// 更新按钮内容
final String updateButtonText;
/// 忽略按钮内容
final String ignoreButtonText;
UpdateWidget(
{Key? key,
this.width = 0.0,
required this.title,
required this.updateContent,
required this.onUpdate,
this.titleTextSize = 16.0,
this.contentTextSize = 14.0,
this.buttonTextSize = 14.0,
this.progress = -1.0,
this.progressBackgroundColor = const Color(0xFFFFCDD2),
this.topImage,
this.extraHeight = 5.0,
this.radius = 4.0,
this.themeColor = Colors.red,
this.enableIgnore = false,
this.onIgnore,
this.isForce = false,
this.updateButtonText = '更新',
this.ignoreButtonText = '忽略此版本',
this.onClose})
: super(key: key);
final _UpdateWidgetState _state = _UpdateWidgetState();
void update(double progress) {
_state.update(progress);
}
@override
_UpdateWidgetState createState() => _state;
}
class _UpdateWidgetState extends State<UpdateWidget> {
void update(double progress) {
if (!mounted) {
return;
}
setState(() {
widget.progress = progress;
});
}
@override
Widget build(BuildContext context) {
final double dialogWidth = widget.width <= 0 ? getFitWidth(context) * 0.618 : widget.width;
return Material(
type: MaterialType.transparency,
child: SizedBox(
width: dialogWidth,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
width: dialogWidth,
child: widget.topImage ?? Image.asset('assets/images/update_bg_app_top.png', fit: BoxFit.fill),
),
Container(
width: dialogWidth,
alignment: Alignment.center,
padding: const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 8),
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(widget.radius), bottomRight: Radius.circular(widget.radius)),
),
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.only(top: widget.extraHeight),
child: Text(widget.title, style: TextStyle(fontSize: widget.titleTextSize, color: Colors.black)),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Text(widget.updateContent, style: TextStyle(fontSize: widget.contentTextSize, color: const Color(0xFF666666))),
),
Column(children: <Widget>[
FractionallySizedBox(
widthFactor: 1,
child: ElevatedButton(
style: ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
textStyle: MaterialStateProperty.all(TextStyle(fontSize: widget.buttonTextSize)),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(5))),
elevation: MaterialStateProperty.all(0),
backgroundColor: MaterialStateProperty.all(widget.themeColor),
),
child: Text(widget.updateButtonText),
onPressed: widget.onUpdate,
),
),
if (widget.enableIgnore && widget.onIgnore != null)
FractionallySizedBox(
widthFactor: 1,
child: TextButton(
style: ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
textStyle: MaterialStateProperty.all(TextStyle(fontSize: widget.buttonTextSize)),
foregroundColor: MaterialStateProperty.all(const Color(0xFF666666)),
shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(5))),
),
child: Text(widget.ignoreButtonText),
onPressed: widget.onIgnore,
))
else
const SizedBox()
]),
],
)),
),
if (!widget.isForce)
Column(children: <Widget>[
const SizedBox(width: 1.5, height: 50, child: DecoratedBox(decoration: BoxDecoration(color: Colors.white))),
IconButton(
iconSize: 30,
constraints: const BoxConstraints(maxHeight: 30, maxWidth: 30),
padding: EdgeInsets.zero,
icon: Image.asset(
'assets/images/update_ic_close.png',
),
onPressed: widget.onClose,
)
])
else
const SizedBox()
],
),
));
}
double getFitWidth(BuildContext context) {
return min(getScreenHeight(context), getScreenWidth(context));
}
double getScreenHeight(BuildContext context) {
return MediaQuery.of(context).size.height;
}
double getScreenWidth(BuildContext context) {
return MediaQuery.of(context).size.width;
}
}

View File

@@ -7,32 +7,14 @@ class Utils {
static final SystemBean systemBean = SystemBean();
static bool isUpperVersion() {
try {
List<String>? version = Utils.systemBean.version?.split("\.");
return systemBean.isUpperVersion();
}
static bool isUpperVersion2_12_2() {
return systemBean.isUpperVersion2_12_2();
}
String f = version?[0] ?? "2";
String s = version?[1] ?? "10";
String t = version?[2] ?? "0";
int first = int.parse(f);
int second = int.parse(s);
int third = int.parse(t);
/// 2.10.13 及以下版本
if (first > 2) {
return true;
}
if (second > 10) {
return true;
}
if (third > 13) {
return true;
}
return false;
} catch (e) {
return false;
}
static bool isUpperVersion2_13_0() {
return systemBean.isUpperVersion2_13_0();
}
static void hideKeyBoard(BuildContext context) {

View File

@@ -1,7 +1,7 @@
name: qinglong_app
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.8+10
version: 1.0.9+11
environment:
sdk: ">=2.15.1 <3.0.0"
@@ -63,7 +63,7 @@ flutter:
assets:
- assets/images/
flutter_app_name:
name: "青龙"
name: "青龙客户端"
flutter_icons:
image_path_android: "assets/images/ql.png"

View File

@@ -1 +1 @@
1.0.8
1.0.9

Binary file not shown.

Before

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -1,112 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="qinglong_app">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>qinglong_app</title>
<link rel="manifest" href="manifest.json">
<script src="splash/splash.js"></script>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<link rel="stylesheet" type="text/css" href="splash/style.css">
</head>
<body>
<picture id="splash">
<source srcset="splash/img/light-1x.png 1x, splash/img/light-2x.png 2x, splash/img/light-3x.png 3x, splash/img/light-4x.png 4x" media="(prefers-color-scheme: light)">
<source srcset="splash/img/dark-1x.png 1x, splash/img/dark-2x.png 2x, splash/img/dark-3x.png 3x, splash/img/dark-4x.png 4x" media="(prefers-color-scheme: dark)">
<img class="center" aria-hidden="true" src="splash/img/light-1x.png" alt=""/>
</picture>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
var serviceWorkerVersion = null;
var scriptLoaded = false;
function loadMainDartJs() {
if (scriptLoaded) {
return;
}
scriptLoaded = true;
var scriptTag = document.createElement('script');
scriptTag.src = 'main.dart.js';
scriptTag.type = 'application/javascript';
document.body.append(scriptTag);
}
if ('serviceWorker' in navigator) {
// Service workers are supported. Use them.
window.addEventListener('load', function () {
// Wait for registration to finish before dropping the <script> tag.
// Otherwise, the browser will load the script multiple times,
// potentially different versions.
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
navigator.serviceWorker.register(serviceWorkerUrl)
.then((reg) => {
function waitForActivation(serviceWorker) {
serviceWorker.addEventListener('statechange', () => {
if (serviceWorker.state == 'activated') {
console.log('Installed new service worker.');
loadMainDartJs();
}
});
}
if (!reg.active && (reg.installing || reg.waiting)) {
// No active web worker and we have installed or are installing
// one for the first time. Simply wait for it to activate.
waitForActivation(reg.installing || reg.waiting);
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
// When the app updates the serviceWorkerVersion changes, so we
// need to ask the service worker to update.
console.log('New service worker available.');
reg.update();
waitForActivation(reg.installing);
} else {
// Existing service worker is still good.
console.log('Loading app from service worker.');
loadMainDartJs();
}
});
// If service worker doesn't succeed in a reasonable amount of time,
// fallback to plaint <script> tag.
setTimeout(() => {
if (!scriptLoaded) {
console.warn(
'Failed to load app from service worker. Falling back to plain <script> tag.',
);
loadMainDartJs();
}
}, 4000);
});
} else {
// Service workers not supported. Just drop the <script> tag.
loadMainDartJs();
}
</script>
</body>
</html>

View File

@@ -1,35 +0,0 @@
{
"name": "qinglong_app",
"short_name": "qinglong_app",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A new Flutter project.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Some files were not shown because too many files have changed in this diff Show More