From 50c2738fc51711c0983b498c5e28112ded8c7f75 Mon Sep 17 00:00:00 2001 From: fengshengxiong Date: Tue, 7 May 2024 18:16:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=90=AD=E5=BB=BA=E6=A1=86=E6=9E=B6=EF=BC=9A?= =?UTF-8?q?=201.=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86=E3=80=81=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E3=80=81=E4=BE=9D=E8=B5=96=E6=B3=A8=E5=85=A5=202.?= =?UTF-8?q?=E5=B1=8F=E5=B9=95=E9=80=82=E9=85=8D=203.=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle | 19 ++- ios/Flutter/Debug.xcconfig | 1 + ios/Flutter/Release.xcconfig | 1 + ios/Podfile | 44 +++++ ios/Runner.xcodeproj/project.pbxproj | 112 +++++++++++++ .../contents.xcworkspacedata | 3 + lib/common/components/easy_loading.dart | 95 +++++++++++ lib/main.dart | 151 +++++------------- lib/modules/home/home_binding.dart | 10 ++ lib/modules/home/home_controller.dart | 5 + lib/modules/home/home_view.dart | 20 +++ lib/routes/app_pages.dart | 24 +++ lib/theme/app_colors.dart | 14 ++ lib/theme/app_themes.dart | 41 +++++ lib/utils/log_print.dart | 50 ++++++ lib/utils/obj_util.dart | 62 +++++++ lib/utils/screen_adapter.dart | 57 +++++++ pubspec.yaml | 26 ++- 18 files changed, 622 insertions(+), 113 deletions(-) create mode 100644 ios/Podfile create mode 100644 lib/common/components/easy_loading.dart create mode 100644 lib/modules/home/home_binding.dart create mode 100644 lib/modules/home/home_controller.dart create mode 100644 lib/modules/home/home_view.dart create mode 100644 lib/routes/app_pages.dart create mode 100644 lib/theme/app_colors.dart create mode 100644 lib/theme/app_themes.dart create mode 100644 lib/utils/log_print.dart create mode 100644 lib/utils/obj_util.dart create mode 100644 lib/utils/screen_adapter.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index e5e56bb..9dc8ad2 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -22,6 +22,10 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } +def keystorePropertiesFile = rootProject.file("key.properties") +def keystoreProperties = new Properties() +keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) + android { namespace "com.lux.ai_clipboard" compileSdk flutter.compileSdkVersion @@ -51,11 +55,24 @@ android { versionName flutterVersionName } + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } + buildTypes { + debug { + signingConfig signingConfigs.release + } + release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig signingConfigs.release } } } diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..d97f17e --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.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__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index adaeec2..3158ad7 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0ABE74C9D7A1B6850A56D488 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E95BA512BB0E58E33F37B1F /* Pods_Runner.framework */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; @@ -14,6 +15,7 @@ 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 */; }; + D84AA34F47188791DD499692 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B38AE4BDC20BE2AFC2CB65C /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -45,9 +47,12 @@ 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 61839213955EECE2FB4FB699 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 88493B7073686043CEF8B534 /* 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 = ""; }; + 8E95BA512BB0E58E33F37B1F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -55,13 +60,27 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9B38AE4BDC20BE2AFC2CB65C /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9D7C4C17A7092A8B91E7FA84 /* 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 = ""; }; + EB6A6A79296C83392931C129 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + F5EFE1CC39EB5410B3E6C12F /* 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 = ""; }; + F9E6BA12E223742B1341B338 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 1C829F9F775AF62840914195 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D84AA34F47188791DD499692 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0ABE74C9D7A1B6850A56D488 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -76,6 +95,15 @@ path = RunnerTests; sourceTree = ""; }; + 7AA509E949A83C076185FD48 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8E95BA512BB0E58E33F37B1F /* Pods_Runner.framework */, + 9B38AE4BDC20BE2AFC2CB65C /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -94,6 +122,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + FFCC0094FE9F29CFF7BF2090 /* Pods */, + 7AA509E949A83C076185FD48 /* Frameworks */, ); sourceTree = ""; }; @@ -121,6 +151,20 @@ path = Runner; sourceTree = ""; }; + FFCC0094FE9F29CFF7BF2090 /* Pods */ = { + isa = PBXGroup; + children = ( + F5EFE1CC39EB5410B3E6C12F /* Pods-Runner.debug.xcconfig */, + 88493B7073686043CEF8B534 /* Pods-Runner.release.xcconfig */, + 9D7C4C17A7092A8B91E7FA84 /* Pods-Runner.profile.xcconfig */, + 61839213955EECE2FB4FB699 /* Pods-RunnerTests.debug.xcconfig */, + EB6A6A79296C83392931C129 /* Pods-RunnerTests.release.xcconfig */, + F9E6BA12E223742B1341B338 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -128,8 +172,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + B738ACD78FD174545EAED834 /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, + 1C829F9F775AF62840914195 /* Frameworks */, ); buildRules = ( ); @@ -145,12 +191,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 7A4E0BA26FE66201864F4B9E /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 01F4835F21AFDE4E4BE112EB /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -222,6 +270,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 01F4835F21AFDE4E4BE112EB /* [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; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -238,6 +303,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 7A4E0BA26FE66201864F4B9E /* [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; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -253,6 +340,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + B738ACD78FD174545EAED834 /* [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-RunnerTests-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 */ @@ -379,6 +488,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 61839213955EECE2FB4FB699 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -396,6 +506,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = EB6A6A79296C83392931C129 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -411,6 +522,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F9E6BA12E223742B1341B338 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/lib/common/components/easy_loading.dart b/lib/common/components/easy_loading.dart new file mode 100644 index 0000000..0d1fee1 --- /dev/null +++ b/lib/common/components/easy_loading.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; + +import '../../theme/app_colors.dart'; + +/// [author] fengshengxiong +/// [date] 2024/5/7 +/// [description] EasyLoading + +/// 配置EasyLoading +void configLoading() { + EasyLoading.instance + + // loading的样式, 默认[EasyLoadingStyle.dark]. + ..loadingStyle = EasyLoadingStyle.custom + + // loading的指示器类型,默认[EasyLoadingIndicatorType.fadingCircle]. + ..indicatorType = EasyLoadingIndicatorType.ring + + // loading的遮罩类型, 默认[EasyLoadingMaskType.none]. + ..maskType = EasyLoadingMaskType.none + + // toast的位置, 默认 [EasyLoadingToastPosition.center]. + ..toastPosition = EasyLoadingToastPosition.center + + // 动画类型, 默认 [EasyLoadingAnimationStyle.opacity]. + ..animationStyle = EasyLoadingAnimationStyle.opacity + + // 文本的对齐方式 , 默认[TextAlign.center]. + ..textAlign = TextAlign.center + + // 文本的样式 , 默认 null + ..textStyle = null + + // 指示器的大小, 默认40.0. + ..indicatorSize = 26.0 + + // loading的圆角大小, 默认5.0. + ..radius = 5.0 + + // 文本大小, 默认15.0. + ..fontSize = 14.0 + + // 进度条指示器的宽度, 默认2.0. + ..progressWidth = 2.0 + + // 指示器的宽度, 默认4.0, 仅对[EasyLoadingIndicatorType.ring, EasyLoadingIndicatorType.dualRing]有效. + ..lineWidth = 2.0 + + // [showSuccess] [showError] [showInfo]的展示时间, 默认2000ms. + ..displayDuration = const Duration(milliseconds: 1000) + + // 动画时间, 默认200ms. + ..animationDuration = const Duration(milliseconds: 200) + + // 文本的颜色, 仅对[EasyLoadingStyle.custom]有效. + ..textColor = white + + // 指示器的颜色, 仅对[EasyLoadingStyle.custom]有效. + ..indicatorColor = white + + // 进度条指示器的颜色, 仅对[EasyLoadingStyle.custom]有效. + ..progressColor = white + + // loading的背景色, 仅对[EasyLoadingStyle.custom]有效. + ..backgroundColor = loadingBg + + // 遮罩的背景色, 仅对[EasyLoadingMaskType.custom]有效. + ..maskColor = black.withOpacity(0.3) + + // 当loading展示的时候,是否允许用户操作. + ..userInteractions = false + + // 点击背景是否关闭. + ..dismissOnTap = false; +} + +void toast(dynamic value, {bool isShow = true}) { + if (isShow) { + EasyLoading.showToast('$value'); + } +} + +void loading({String? value, bool isShow = true}) { + if (isShow) { + EasyLoading.show(status: value); + } +} + +void dismiss({bool isDismiss = true}) { + if (isDismiss) { + EasyLoading.dismiss(); + } +} + diff --git a/lib/main.dart b/lib/main.dart index 8e94089..c4397a6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,125 +1,54 @@ +import 'package:ai_clipboard/routes/app_pages.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'common/components/easy_loading.dart'; +import 'theme/app_themes.dart'; void main() { runApp(const MyApp()); + + // 配置EasyLoading + configLoading(); } class MyApp extends StatelessWidget { const MyApp({super.key}); - // This widget is the root of your application. @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - // This is the theme of your application. - // - // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a purple toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. - colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), - useMaterial3: true, - ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), - ); - } -} - -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - final String title; - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // TRY THIS: Try changing the color here to a specific color (to - // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar - // change color while the other colors stay the same. - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - // - // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" - // action in the IDE, or press "p" in the console), to see the - // wireframe for each widget. - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), - ), // This trailing comma makes auto-formatting nicer for build methods. + final easyLoading = EasyLoading.init(); + return ScreenUtilInit( + // 设计稿中设备的尺寸(单位随意,建议dp,但在使用过程中必须保持一致) + designSize: const Size(360, 690), + // 是否根据宽度/高度中的最小值适配文字 + minTextAdapt: true, + // 支持分屏尺寸 + splitScreenMode: true, + builder: (context, child) { + return GetMaterialApp( + title: 'AI Clipboard', + theme: lightTheme, + darkTheme: darkTheme, + themeMode: ThemeMode.light, + getPages: AppPages.routes, + initialRoute: AppPages.initial, + builder: (context, widget) { + widget = easyLoading(context, widget); + return MediaQuery( + // 设置文字大小不随系统设置改变 + data: MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling), + child: KeyboardDismissOnTap( + // 点击其他交互式组件,也关闭键盘 + dismissOnCapturedTaps: true, + child: widget, + ), + ); + }, + ); + }, ); } } diff --git a/lib/modules/home/home_binding.dart b/lib/modules/home/home_binding.dart new file mode 100644 index 0000000..0905989 --- /dev/null +++ b/lib/modules/home/home_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'home_controller.dart'; + +class HomeBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => HomeController()); + } +} diff --git a/lib/modules/home/home_controller.dart b/lib/modules/home/home_controller.dart new file mode 100644 index 0000000..9f5a6fc --- /dev/null +++ b/lib/modules/home/home_controller.dart @@ -0,0 +1,5 @@ +import 'package:get/get.dart'; + +class HomeController extends GetxController { + +} diff --git a/lib/modules/home/home_view.dart b/lib/modules/home/home_view.dart new file mode 100644 index 0000000..1aadeee --- /dev/null +++ b/lib/modules/home/home_view.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'home_controller.dart'; + +class HomeView extends GetView { + const HomeView({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('AI Clipboard'), + ), + body: const Center( + child: Text('AI Clipboard'), + ), + ); + } +} diff --git a/lib/routes/app_pages.dart b/lib/routes/app_pages.dart new file mode 100644 index 0000000..5be1884 --- /dev/null +++ b/lib/routes/app_pages.dart @@ -0,0 +1,24 @@ +import 'package:ai_clipboard/modules/home/home_view.dart'; +import 'package:get/get.dart'; + +import '../modules/home/home_binding.dart'; + +/// [author] fengshengxiong +/// [date] 2024/5/7 +/// [description] 路由配置 + +class AppPages { + AppPages._(); + + static const initial = '/home'; + + static final routes = [ + GetPage( + name: initial, + page: () => const HomeView(), + bindings: [HomeBinding()], + participatesInRootNavigator: true, + preventDuplicates: true, + ), + ]; +} \ No newline at end of file diff --git a/lib/theme/app_colors.dart b/lib/theme/app_colors.dart new file mode 100644 index 0000000..f43a811 --- /dev/null +++ b/lib/theme/app_colors.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; + +/// [author] fengshengxiong +/// [date] 2024/5/7 +/// [description] 颜色 + +/// 主要颜色 +const primary = Colors.deepPurple; + +const white = Colors.white; + +const black = Colors.black; + +const loadingBg = Color(0xFF616161); \ No newline at end of file diff --git a/lib/theme/app_themes.dart b/lib/theme/app_themes.dart new file mode 100644 index 0000000..f65857c --- /dev/null +++ b/lib/theme/app_themes.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +import 'app_colors.dart'; + +/// [author] fengshengxiong +/// [date] 2024/5/7 +/// [description] 主题 + +/// 浅色主题 +ThemeData lightTheme = ThemeData.light(useMaterial3: true).copyWith( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + primaryColor: primary, + scaffoldBackgroundColor: white, + appBarTheme: AppBarTheme( + systemOverlayStyle: SystemUiOverlayStyle.light, + backgroundColor: primary, + iconTheme: const IconThemeData(color: white), + elevation: 0.0, + centerTitle: true, + titleTextStyle: TextStyle(color: white, fontSize: 25.sp, fontWeight: FontWeight.w500), + ), + textSelectionTheme: const TextSelectionThemeData( + cursorColor: primary, + selectionHandleColor: primary, + ), +); + +/// 深色主题 +ThemeData darkTheme = ThemeData.dark(useMaterial3: true).copyWith( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + primaryColor: primary, + scaffoldBackgroundColor: ThemeData.light().scaffoldBackgroundColor, + appBarTheme: AppBarTheme( + elevation: 0.0, + systemOverlayStyle: SystemUiOverlayStyle.dark, + backgroundColor: ThemeData.light().scaffoldBackgroundColor, + iconTheme: const IconThemeData(color: Colors.black), + ), +); \ No newline at end of file diff --git a/lib/utils/log_print.dart b/lib/utils/log_print.dart new file mode 100644 index 0000000..6742dd1 --- /dev/null +++ b/lib/utils/log_print.dart @@ -0,0 +1,50 @@ +import 'package:logger/logger.dart'; + +/// [author] fengshengxiong +/// [date] 2024/5/7 +/// [description] 日志打印 + +final _logger = Logger( + printer: PrettyPrinter( + // 要显示的方法调用的数量 + methodCount: 0, + // 如果提供了stacktrace,则方法调用的数量 + errorMethodCount: 8, + // 输出的宽度 + lineLength: 120, + // 丰富多彩的日志消息 + colors: true, + // 是否打印表情符号 + printEmojis: true, + // 是否打印时间 + printTime: false, + ), +); + +class LogPrint { + static const String _tag = 'AI Clipboard Log'; + + LogPrint.t(dynamic msg, {String tag = _tag}) { + _logger.t('[$tag]: $msg'); + } + + LogPrint.d(dynamic msg, {String tag = _tag}) { + _logger.d('[$tag]: $msg'); + } + + LogPrint.i(dynamic msg, {String tag = _tag}) { + _logger.i('[$tag]: $msg'); + } + + LogPrint.w(dynamic msg, {String tag = _tag}) { + _logger.w('[$tag]: $msg'); + } + + LogPrint.e(dynamic msg, {String tag = _tag}) { + _logger.e('[$tag]: $msg'); + } + + LogPrint.f(dynamic msg, {String tag = _tag}) { + _logger.f('[$tag]: $msg'); + } +} \ No newline at end of file diff --git a/lib/utils/obj_util.dart b/lib/utils/obj_util.dart new file mode 100644 index 0000000..3d23281 --- /dev/null +++ b/lib/utils/obj_util.dart @@ -0,0 +1,62 @@ +/// [author] fengshengxiong +/// [date] 2024/5/7 +/// [description] 对象工具类 +library; + +class ObjUtil { + static bool isNotEmptyString(String? str) { + return str == null || str.trim().isNotEmpty; + } + + static bool isNotEmptyList(Iterable? list) { + return list == null || list.isNotEmpty; + } + + static bool isNotEmptyMap(Map? map) { + return map == null || map.isNotEmpty; + } + + static bool isEmpty(Object? object) { + if (object == null) return true; + if (object is String && object.trim().isEmpty) { + return true; + } else if (object is Iterable && object.isEmpty) { + return true; + } else if (object is Map && object.isEmpty) { + return true; + } + return false; + } + + static bool isNotEmpty(Object? object) { + return !isEmpty(object); + } + + /// Returns true Two List Is Equal. + static bool twoListIsEqual(List? listA, List? listB) { + if (listA == listB) return true; + if (listA == null || listB == null) return false; + int length = listA.length; + if (length != listB.length) return false; + for (int i = 0; i < length; i++) { + if (!listA.contains(listB[i])) { + return false; + } + } + return true; + } + + /// get length. + static int getLength(Object? value) { + if (value == null) return 0; + if (value is String) { + return value.length; + } else if (value is Iterable) { + return value.length; + } else if (value is Map) { + return value.length; + } else { + return 0; + } + } +} \ No newline at end of file diff --git a/lib/utils/screen_adapter.dart b/lib/utils/screen_adapter.dart new file mode 100644 index 0000000..658c02f --- /dev/null +++ b/lib/utils/screen_adapter.dart @@ -0,0 +1,57 @@ +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +/// [author] fengshengxiong +/// [date] 2024/5/7 +/// [description] 屏幕适配器 + +class ScreenAdapter { + /// 当前设备宽度 dp + static getScreenWidth() { + return ScreenUtil().screenWidth; + } + + /// 当前设备高度 dp + static getScreenHeight() { + return ScreenUtil().screenHeight; + } + + /// 屏幕宽度的倍数 + static sw(num value) { + return value.sw; + } + + /// 屏幕高度的倍数 + static sh(num value) { + return value.sh; + } + + /// 状态栏高度 dp 刘海屏会更高 + static getStatusBarHeight() { + return ScreenUtil().statusBarHeight; + } + + /// 底部安全区距离 dp + static getBottomSafeAreaHeight() { + return ScreenUtil().bottomBarHeight; + } + + /// [ScreenUtil.setWidth] + static w(num value) { + return value.w; + } + + /// [ScreenUtil.setHeight] + static h(num value) { + return value.h; + } + + /// [ScreenUtil.radius] + static r(num value) { + return value.r; + } + + /// [ScreenUtil.setSp] + static sp(num value) { + return value.sp; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 59519ec..e834f9c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,6 +36,30 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.6 + # 状态管理、路由、依赖注入 + get: ^4.6.6 + + # 网络库 + dio: ^5.4.3+1 + + # 屏幕和字体大小适配 + flutter_screenutil: ^5.9.0 + + # 显示网络图像并将它们保存在缓存目录中 + cached_network_image: ^3.3.1 + + # 对键盘可见性变化做出反应 + flutter_keyboard_visibility: ^6.0.0 + + # 加载、进度、提示框 + flutter_easyloading: ^3.0.5 + + # 获取当前设备信息 + device_info_plus: ^10.1.0 + + # 日志打印 + logger: ^2.2.0 + dev_dependencies: flutter_test: sdk: flutter @@ -45,7 +69,7 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^3.0.0 + flutter_lints: ^3.0.2 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec