diff --git a/.gitignore b/.gitignore index 6d21af3..29a3a50 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,43 @@ -# See https://www.dartlang.org/guides/libraries/private-files +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ -# Files and directories created by pub +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id .dart_tool/ -.packages -build/ -# If you're building an application, you may want to check-in your pubspec.lock -pubspec.lock - -# Directory created by dartdoc -# If you don't generate documentation locally you can remove this line. -doc/api/ - -# Avoid committing generated Javascript files: -*.dart.js -*.info.json # Produced by the --dump-info flag. -*.js # When generated by dart2js. Don't specify *.js if your - # project includes source files written in JavaScript. -*.js_ -*.js.deps -*.js.map - .flutter-plugins .flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..b5c370f --- /dev/null +++ b/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "41456452f29d64e8deb623a3c927524bcf9f111b" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: android + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: ios + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: linux + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: macos + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: web + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: windows + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/README.en.md b/README.en.md deleted file mode 100644 index c32fc1e..0000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# huaxin-base-mobile - -#### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..7766687 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,67 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +android { + namespace "com.sdmm.manage" + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.sdmm.manage" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + 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 + } + } +} + +flutter { + source '../..' +} + +dependencies {} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c3cbeff --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/sk_base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/sk_base_app/MainActivity.kt new file mode 100644 index 0000000..51dfce1 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/sk_base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.sdmm.manage + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/android/app/src/main/res/drawable-v21/background.png b/android/app/src/main/res/drawable-v21/background.png new file mode 100644 index 0000000..06b2f8f Binary files /dev/null and b/android/app/src/main/res/drawable-v21/background.png differ diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f88598c --- /dev/null +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png new file mode 100644 index 0000000..06b2f8f Binary files /dev/null and b/android/app/src/main/res/drawable/background.png differ diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..f88598c --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000..107f320 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png new file mode 100644 index 0000000..de04455 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000..2a7ffb1 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000..a450896 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png new file mode 100644 index 0000000..1d6af1c Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/values-night-v31/styles.xml b/android/app/src/main/res/values-night-v31/styles.xml new file mode 100644 index 0000000..a3653cb --- /dev/null +++ b/android/app/src/main/res/values-night-v31/styles.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..dbc9ea9 --- /dev/null +++ b/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/android/app/src/main/res/values-v31/styles.xml b/android/app/src/main/res/values-v31/styles.xml new file mode 100644 index 0000000..d0a68e9 --- /dev/null +++ b/android/app/src/main/res/values-v31/styles.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..0d1fa8f --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..e83fb5d --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,30 @@ +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..598d13f --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..3c472b9 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..7cd7128 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,29 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + } + settings.ext.flutterSdkPath = flutterSdkPath() + + includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } + + plugins { + id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false +} + +include ":app" diff --git a/assets/fonts/NotoSans-Bold.ttf b/assets/fonts/NotoSans-Bold.ttf new file mode 100644 index 0000000..c740dbf Binary files /dev/null and b/assets/fonts/NotoSans-Bold.ttf differ diff --git a/assets/fonts/NotoSans-Medium.ttf b/assets/fonts/NotoSans-Medium.ttf new file mode 100644 index 0000000..47d1bbb Binary files /dev/null and b/assets/fonts/NotoSans-Medium.ttf differ diff --git a/assets/fonts/NotoSans-Regular.ttf b/assets/fonts/NotoSans-Regular.ttf new file mode 100644 index 0000000..e00e507 Binary files /dev/null and b/assets/fonts/NotoSans-Regular.ttf differ diff --git a/assets/fonts/NotoSans-SemiBold.ttf b/assets/fonts/NotoSans-SemiBold.ttf new file mode 100644 index 0000000..3007211 Binary files /dev/null and b/assets/fonts/NotoSans-SemiBold.ttf differ diff --git a/assets/icons/logo.png b/assets/icons/logo.png new file mode 100644 index 0000000..386a5a4 Binary files /dev/null and b/assets/icons/logo.png differ diff --git a/assets/images/apple_login.png b/assets/images/apple_login.png new file mode 100644 index 0000000..cf87a74 Binary files /dev/null and b/assets/images/apple_login.png differ diff --git a/assets/images/background.png b/assets/images/background.png new file mode 100644 index 0000000..0bd320f Binary files /dev/null and b/assets/images/background.png differ diff --git a/assets/images/fast_login.png b/assets/images/fast_login.png new file mode 100644 index 0000000..9fb12c7 Binary files /dev/null and b/assets/images/fast_login.png differ diff --git a/assets/images/icons.png b/assets/images/icons.png new file mode 100644 index 0000000..9b4195f Binary files /dev/null and b/assets/images/icons.png differ diff --git a/assets/images/launch_image.jpg b/assets/images/launch_image.jpg new file mode 100644 index 0000000..86d9e92 Binary files /dev/null and b/assets/images/launch_image.jpg differ diff --git a/assets/images/signIn01.png b/assets/images/signIn01.png new file mode 100644 index 0000000..773e4b3 Binary files /dev/null and b/assets/images/signIn01.png differ diff --git a/assets/images/signIn02.png b/assets/images/signIn02.png new file mode 100644 index 0000000..17c31cc Binary files /dev/null and b/assets/images/signIn02.png differ diff --git a/assets/images/signUp01.png b/assets/images/signUp01.png new file mode 100644 index 0000000..c51e85b Binary files /dev/null and b/assets/images/signUp01.png differ diff --git a/assets/images/signUp02.png b/assets/images/signUp02.png new file mode 100644 index 0000000..4e9d3a6 Binary files /dev/null and b/assets/images/signUp02.png differ diff --git a/flutter_native_splash.yaml b/flutter_native_splash.yaml new file mode 100644 index 0000000..8adc6ed --- /dev/null +++ b/flutter_native_splash.yaml @@ -0,0 +1,2 @@ +flutter_native_splash: + background_image: 'assets/images/launch_image.jpg' diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,34 @@ +**/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 diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..7c56964 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e52f5df --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,614 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 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 */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy 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 */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; 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 = ""; }; + 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; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 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 = ""; }; + 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; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 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 = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807E294A63A400263BE5 /* Frameworks */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + 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 = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 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 */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 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; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + 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; + alwaysOutOfDate = 1; + 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"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* 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_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)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.skBaseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.skBaseApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.skBaseApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.skBaseApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + 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_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_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)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.skBaseApp; + 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)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.skBaseApp; + 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 */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 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 */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..87131a0 --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +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) + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "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" + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..121cb25 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..5bf84bf Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..ac89260 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..99092b8 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..b252917 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..f2c7472 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..65600fd Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..ac89260 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..6c81302 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..a3a5fdc Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000..d52a60b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000..ab24f4c Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..348bfd8 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..7916b37 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..a3a5fdc Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..eeec3ff Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..107f320 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..a450896 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..780835b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..5c28ea3 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..a82ea5f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json new file mode 100644 index 0000000..9f447e1 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "background.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png new file mode 100644 index 0000000..06b2f8f Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..00cabce --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "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 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..71e9c81 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..71e9c81 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..71e9c81 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# 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. \ No newline at end of file diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..55c0cae --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist new file mode 100644 index 0000000..d9ed424 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Sk Base App + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + sk_base_mobile + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + UIStatusBarHidden + + + diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/ios/RunnerTests/RunnerTests.swift b/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/lib/apis/api.dart b/lib/apis/api.dart new file mode 100644 index 0000000..5b17a1b --- /dev/null +++ b/lib/apis/api.dart @@ -0,0 +1,67 @@ +import 'dart:async'; +import 'dart:io'; +import 'package:dio/dio.dart'; +import 'package:sk_base_mobile/constants/global_url.dart'; +import 'package:sk_base_mobile/services/dio.service.dart'; +import '../constants/constants.dart'; + +Future login(String? oauthType, String? token) { + return DioService.dio.post(Urls.login, + data: {'oauthType': oauthType, 'token': token}, + options: Options(contentType: "application/x-www-form-urlencoded")); +} + +Future logout() { + return DioService.dio.post( + Urls.logout, + ); +} + +Future deleteAccount() { + return DioService.dio.post( + Urls.deleteAccount, + ); +} + +Future getAppConfig() { + Map query = {'ver': 0}; + return DioService.dio.get(Urls.getAppConfig, queryParameters: query); +} + +Future saveUserInfo(Map data) { + return DioService.dio.post(Urls.saveUserInfo, data: data); +} + +Future getUserInfo(String userId) { + Map data = { + "userId": userId, + }; + return DioService.dio.get(Urls.getUserInfo, queryParameters: data); +} + +Future uploadImg(File file) async { + // DateTime dateTime = DateTime.now(); + // String fileName = file.path.split('/').last; + // String format = fileName.split('.').last; + // int imageTimeName = dateTime.millisecondsSinceEpoch + + // (dateTime.microsecondsSinceEpoch ~/ 1000000); + // String imageName = '$imageTimeName.$format'; + // String host = AppInfoService.to.ossPolicy.host!; + // String dir = AppInfoService.to.ossPolicy.dir!; + // final filePath = await MultipartFile.fromFile(file.path, filename: fileName); + // final formData = FormData.fromMap({ + // 'ossaccessKeyId': AppInfoService.to.ossPolicy.accessKeyId, + // 'policy': AppInfoService.to.ossPolicy.policy, + // 'signature': AppInfoService.to.ossPolicy.signature, + // 'callback': AppInfoService.to.ossPolicy.callback, + // 'key': '$dir/$imageName', + // 'file': filePath, + // }); + + // return DioService.dio.post(host, data: formData); + return {} as Response; +} + +Future updateAvatar(String filename) { + return DioService.dio.post(Urls.updateAvatar, data: {'avatarPath': filename}); +} diff --git a/lib/app_theme.dart b/lib/app_theme.dart new file mode 100644 index 0000000..5db6784 --- /dev/null +++ b/lib/app_theme.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:sk_base_mobile/util/screen_adaper_util.dart'; + +class AppTheme { + AppTheme._(); + static const Color primaryColor = Color(0xFFB0F320); + static const Color primaryColorDark = Color(0xFFABEE1C); + static const Color nearlyWhite = Color(0xFFFEFEFE); + static const Color white = Color(0xFFFFFFFF); + static const Color nearlyBlack = Color(0xFF213333); + static const Color grey = Color(0xFF3A5160); + static const Color dark_grey = Color(0xFF313A44); + static const Color snackbarErrorBackgroudColor = Colors.red; + static const Color snackbarSuccessBackgroudColor = Colors.green; + static const Color snackbarWarningBackgroudColor = Colors.orange; + static const Color roleIconBackgroudColor = Color(0xff002f5f); + static const Color fixturePublishStatusColor = Color(0xFF5B8C00); + static const Color fixtureNotPublishStatusColor = Color(0xFFD7616E); + static const Color darkText = Color(0xFF253840); + static const Color darkerText = Color(0xFF17262A); + static const Color lightText = Color(0xFF4A6572); + static const Color dismissibleBackground = Color(0xFF364A54); + static const String fontName = 'NotoSans'; +} + +final theme = ThemeData( + fontFamily: AppTheme.fontName, + // primarySwatch:MaterialColor() AppTheme.primaryColor, + visualDensity: VisualDensity.adaptivePlatformDensity, + primaryColor: AppTheme.primaryColor, + primaryColorDark: AppTheme.primaryColorDark, + progressIndicatorTheme: + ProgressIndicatorThemeData(color: AppTheme.primaryColor), + dividerColor: Color(0xFFDBDBDA), + cardColor: Colors.white, + scaffoldBackgroundColor: Color(0xFFF8F8F8), + tabBarTheme: TabBarTheme( + indicator: BoxDecoration( + border: + Border(bottom: BorderSide(width: 3, color: AppTheme.primaryColorDark)), + )), + appBarTheme: AppBarTheme( + centerTitle: true, + iconTheme: IconThemeData(color: Colors.black), + backgroundColor: AppTheme.primaryColor, + titleTextStyle: TextStyle( + color: Colors.black, + fontSize: ScreenAdaper.sp(20), + fontWeight: FontWeight.bold), + ), +); diff --git a/lib/config.dart b/lib/config.dart new file mode 100644 index 0000000..dd66a9b --- /dev/null +++ b/lib/config.dart @@ -0,0 +1,9 @@ +/// Global config +class GloablConfig { + static const BASE_URL = "http://172.21.128.1:3000/"; + static const DOMAIN_NAME = "山矿通"; + static const DEBUG = true; + static const PRIVACY_POLICY = 'http://h5.heeru.xyz/privacyPolicy.html'; + static const TERM_OF_USER = 'http://h5.heeru.xyz/termConditions.html'; + static const APPLE_STORE_PAGE = 'https://apps.apple.com/cn/app'; +} diff --git a/lib/constants/cache_key.dart b/lib/constants/cache_key.dart new file mode 100644 index 0000000..5a08ad1 --- /dev/null +++ b/lib/constants/cache_key.dart @@ -0,0 +1,10 @@ +class CacheKeys { + static String appConfig = 'appConfig'; + static String ver = 'ver'; + static String token = 'token'; + static String userInfo = 'userInfo'; + static String deviceUUID = 'deviceUUID'; + static String deviceModel = 'deviceModel'; + static String packageName = 'packageName'; + static String isFirstInstall = 'isFirstInstall'; +} diff --git a/lib/constants/constants.dart b/lib/constants/constants.dart new file mode 100644 index 0000000..20b3a87 --- /dev/null +++ b/lib/constants/constants.dart @@ -0,0 +1,7 @@ +library constants; + +export 'data.dart'; +export 'enum.dart'; +export 'global_url.dart'; +export 'cache_key.dart'; +export 'router.dart'; diff --git a/lib/constants/data.dart b/lib/constants/data.dart new file mode 100644 index 0000000..dd615e3 --- /dev/null +++ b/lib/constants/data.dart @@ -0,0 +1,93 @@ +class Data { + static const parkDetail = { + "elephant": { + "title": "Huge elephant", + "bannerCount": "4", + "isTranslating": false, + "translatedText": null, + "content": + "The elephant is the largest land animal in the world. Its pillar-like limbs and broad paws hold its huge body steady. The huge head has large bushy ears and a long, flexible trunk. The elephant\"s ears are richly vascularized to dissipate heat efficiently. The trunk and upper lip are integrated into a single trunk coordinated by more than 15,000 muscles." + }, + "raccoon": { + "title": "Cute raccoon", + "bannerCount": "5", + "isTranslating": false, + "translatedText": null, + "content": + "Raccoons are mainly found in Europe and North America, and are now found all over the world. Raccoons like to live in woods near rivers, lakes, or ponds. They are carnivores, but tend to be omnivores. Their diet in spring and early summer is mainly insects, worms, etc. In late summer, autumn and winter, it prefers to eat fruits and nuts. It is nocturnal, resting mostly on trees or tree holes during the day, and only comes out at night. Come winter, northern raccoons hibernate." + }, + "deer": { + "title": "Running deer", + "bannerCount": "5", + "isTranslating": false, + "translatedText": null, + "content": + "The Cervidae family belongs to the order Artiodactyla. The common characteristics of deer species are: the coat is gray, tan, reddish brown and yellow; there is a black bare area at the end of the snout (except reindeer); the tails of most species are relatively short, and elk tails are the longest; there are obvious black spots under the eyes Concave tear pit; each foot has 4 hooves, and the hoof shape is small; except for a few species, the canine teeth of most species have degenerated or disappeared." + }, + "squirrel": { + "title": "Delicate squirrel", + "bannerCount": "5", + "isTranslating": false, + "translatedText": null, + "content": + "Squirrel is a mammal of the genus Squirrel in the family Squiridae of the order Rodentia. The body of the squirrel is slender, with longer hind limbs; there are no skin wings between the front and rear limbs, and the limbs are strong; the eyes are large and bright, the ears are long, and there is a tuft of hair at the tip of the ear, which is especially noticeable in winter; the summer hair is generally dark brown or auburn, and the winter hair is They are mostly gray, smoky gray or gray brown, with white abdominal hair; there are sharp hooks on the fingers and toes, and the tail hairs are numerous and fluffy, often curled toward the back. Female squirrels are slightly heavier than males." + }, + "swan": { + "title": "Noble swan", + "bannerCount": "4", + "isTranslating": false, + "translatedText": null, + "content": + "Swans are distributed on all continents except Africa and Antarctica, and mainly inhabit large lakes or swamps with rich aquatic plants. Swans are a winter migratory bird. Every year in March and April, they fly in groups from the south to the north to lay eggs and reproduce. After October, they migrate south again in groups and overwinter in the warmer climate in the south. When flying, swans often form small groups of six to twenty, flying and singing at a very fast speed." + } + }; + static List countryCodes = [ + "ARE", + "ARG", + "AUS", + "AUT", + "BEL", + "BRA", + "CAN", + "CHE", + "COL", + "DEU", + "DNK", + "EGY", + "ESP", + "FRA", + "GBR", + "HKG", // 香港 + "IDN", + "IND", + "ITA", + "JPN", + "MAC", // 澳门 + "MEX", + "MYS", + "NLD", + "NOR", + "PER", + "PHL", + "POL", + "PRT", + "RUS", + "SAU", + "SGP", + "SWE", + "THA", + "TWN", // 台湾 + "TUR", + "USA", + "VEN", + "ZAF", + ]; + + static Map rankTicketPrice = { + 'elephant': 999, + 'deer': 299, + 'raccoon': 399, + 'swan': 899, + 'squirrel': 399 + }; +} diff --git a/lib/constants/enum.dart b/lib/constants/enum.dart new file mode 100644 index 0000000..358a6e1 --- /dev/null +++ b/lib/constants/enum.dart @@ -0,0 +1,5 @@ +enum BackActionEnum { + refresh, +} + +enum LoginEnum { apple, fastLogin } diff --git a/lib/constants/global_url.dart b/lib/constants/global_url.dart new file mode 100644 index 0000000..8d9d512 --- /dev/null +++ b/lib/constants/global_url.dart @@ -0,0 +1,27 @@ +class Urls { + static String getAppConfig = 'config/getAppConfig'; + static String login = 'security/oauth'; + static String isValidToken = 'security/isValidToken'; + static String logout = 'security/logout'; + static String deleteAccount = 'user/deleteAccount'; + static String rankList = 'broadcaster/wall/search'; + static String addFriend = 'user/addFriend'; + static String removeFriend = 'user/unfriend'; + static String goodsList = 'coin/goods/search'; + static String saveUserInfo = 'user/saveUserInfo'; + static String getUserInfo = 'user/getUserInfo'; + static String getOssPolicy = 'user/oss/policy'; + static String updateAvatar = 'user/updateAvatar'; + static String getFollowedList = 'user/getFriendsListPage'; + static String reportComplain = 'report/complain/insertRecord'; + static String blockList = 'report/complain/blockList'; + static String unblock = 'report/complain/removeBlock'; + static String googleTranslate = + 'https://translation.googleapis.com/language/translate/v2'; + static String getIMStrategy = 'config/getStrategy'; + static String getIMToken = 'user/rongcloud/token'; + static String trackingLog = 'log/live-chat'; + static String createOrder = 'coin/recharge/create'; + static String validateOrder = 'coin/recharge/payment/ipa'; + static String reviewModeConsume = 'coin/reviewModeConsume'; +} diff --git a/lib/constants/router.dart b/lib/constants/router.dart new file mode 100644 index 0000000..9fef4f0 --- /dev/null +++ b/lib/constants/router.dart @@ -0,0 +1,16 @@ +import 'package:get/get.dart'; +import 'package:sk_base_mobile/screens/login/login.dart'; + +import '../screens/landing/zt_landing.dart'; +import '../screens/mine/useinfo/userinfo.dart'; + +class RouteConfig { + static const String home = "/"; + static const String login = '/login'; + static const String userinfo = '/userinfo'; + static final List getPages = [ + GetPage(name: login, page: () => LoginScreen()), + GetPage(name: home, page: () => LandingPage()), + GetPage(name: userinfo, page: () => UserInfoPage()), + ]; +} diff --git a/lib/global.dart b/lib/global.dart new file mode 100644 index 0000000..7af266c --- /dev/null +++ b/lib/global.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get/get.dart'; +import 'package:timeago/timeago.dart' as timeago; +import 'package:sk_base_mobile/constants/cache_key.dart'; +import 'package:sk_base_mobile/services/app_info.service.dart'; +import 'package:sk_base_mobile/services/dio.service.dart'; +import 'package:sk_base_mobile/services/storage.service.dart'; +import 'store/store.dart'; + +/// 全局注册 +class Global { + static Future init() async { + WidgetsFlutterBinding.ensureInitialized(); + + /// 设置初始化竖屏 + await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + + /// 设置系统UI 因用户反馈可能存在bug先隐藏功能 + setSystemUi(); + + /// 初始化 几天前 的时区国际化 + timeago.setLocaleMessages('en', timeago.EnMessages()); + + /// 依赖注入持久化 + await Get.putAsync(() => StorageService().init()); + + /// 依赖注入Http + await Get.putAsync(() => DioService().init()); + + /// 依赖注入app信息 + await Get.putAsync(() => AppInfoService().init()); + + /// 依赖注入用户信息 + await Get.putAsync(() => AuthStore().init()); + + if (StorageService.to.getString(CacheKeys.token, isWithUser: false) != + null) { + /// 这里做一些缓存初始化后的操作 + } + } + + static void setSystemUi() { + SystemUiOverlayStyle systemUiOverlayStyle = const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + ); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + } +} diff --git a/lib/index.dart b/lib/index.dart new file mode 100644 index 0000000..d48df4d --- /dev/null +++ b/lib/index.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:sk_base_mobile/config.dart'; +import 'package:sk_base_mobile/services/storage.service.dart'; +import 'package:sk_base_mobile/app_theme.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:sk_base_mobile/widgets/refresh-footer.dart'; +import 'package:sk_base_mobile/widgets/refresh_header.dart'; + +import 'constants/constants.dart'; +import 'services/app_info.service.dart'; + +// The index screen shows login if no user identity was found, otherwise the landing screen +class IndexPage extends StatelessWidget { + const IndexPage({super.key}); + @override + Widget build(BuildContext context) { + return ScreenUtilInit( + minTextAdapt: true, + designSize: const Size(932, 1490), // 2800 * 1800p 309ppi + builder: (buildContext, child) => RefreshConfiguration( + headerBuilder: () => RefreshHeader(), + footerBuilder: () => const RefreshFooter(), + hideFooterWhenNotFull: true, + headerTriggerDistance: 30, + maxOverScrollExtent: 80, + footerTriggerDistance: 150, + child: GetMaterialApp( + theme: theme, + title: GloablConfig.DOMAIN_NAME, + getPages: RouteConfig.getPages, + initialRoute: getInitialRoute(), + // initialRoute: RouteConfig.onboarding, + debugShowCheckedModeBanner: false, + builder: (_, widget) => Obx(() => MediaQuery( + //设置文字大小不随系统设置改变 + data: MediaQuery.of(context).copyWith( + textScaleFactor: AppInfoService.to.scale.value), + child: GestureDetector( + onTap: () { + FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus && + currentFocus.focusedChild != null) { + FocusManager.instance.primaryFocus?.unfocus(); + } + }, + child: widget!, + )))))); + } + + String getInitialRoute() { + if (AppInfoService.to.checkIsFirstInstall()) { + // 如果是第一次打开app打开的页面 + } + return StorageService.to.getString(CacheKeys.token, isWithUser: false) == + null + ? RouteConfig.login + : RouteConfig.home; + } +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..4c29cdd --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; +import 'package:sk_base_mobile/global.dart'; +import 'package:sk_base_mobile/index.dart'; +import 'package:sk_base_mobile/util/logger_util.dart'; + +Future main() async { + try { + await Global.init(); + } catch (e) { + LoggerUtil().error('Init failed, please try again.${e}'); + } + + runApp(const IndexPage()); +} diff --git a/lib/models/app_bottom_nav_item.dart b/lib/models/app_bottom_nav_item.dart new file mode 100644 index 0000000..b8747d4 --- /dev/null +++ b/lib/models/app_bottom_nav_item.dart @@ -0,0 +1,9 @@ +import 'package:flutter/cupertino.dart'; + +class AppBottomNavItem { + String? icon; + String? activeIcon; + String? label; + Widget? page; + AppBottomNavItem({this.icon, this.activeIcon, this.label, this.page}); +} diff --git a/lib/models/app_config.dart b/lib/models/app_config.dart new file mode 100644 index 0000000..b67c18c --- /dev/null +++ b/lib/models/app_config.dart @@ -0,0 +1,44 @@ +class AppConfig { + String? ver; + List? items; + + AppConfig({this.ver, this.items}); + + AppConfig.fromJson(Map json) { + ver = json['ver']; + if (json['items'] != null) { + items = []; + json['items'].forEach((v) { + items!.add(AppConfigItem.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = Map(); + data['ver'] = ver; + if (items != null) { + data['items'] = items!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class AppConfigItem { + dynamic data; + String? name; + + AppConfigItem({this.data, name}); + + AppConfigItem.fromJson(Map json) { + data = json['data']; + name = json['name']; + } + + Map toJson() { + final Map json = new Map(); + json['data'] = data; + json['name'] = name; + return json; + } +} diff --git a/lib/models/auth.dart b/lib/models/auth.dart new file mode 100644 index 0000000..b122d08 --- /dev/null +++ b/lib/models/auth.dart @@ -0,0 +1,27 @@ +import 'package:sk_base_mobile/models/user_info.model.dart'; + +class Auth { + bool? isFirstRegister; + String? token; + UserInfoModel? userInfo; + + Auth({this.isFirstRegister, this.token, this.userInfo}); + + Auth.fromJson(Map json) { + isFirstRegister = json['isFirstRegister']; + token = json['token']; + userInfo = json['userInfo'] != null + ? UserInfoModel.fromJson(json['userInfo']) + : null; + } + + Map toJson() { + final Map data = Map(); + data['isFirstRegister'] = isFirstRegister; + data['token'] = token; + if (userInfo != null) { + data['userInfo'] = userInfo!.toJson(); + } + return data; + } +} diff --git a/lib/models/base_model.dart b/lib/models/base_model.dart new file mode 100644 index 0000000..889281a --- /dev/null +++ b/lib/models/base_model.dart @@ -0,0 +1,8 @@ +class BaseModel { + BaseModel.fromJson(Map json) {} + + Map toJson() { + final Map data = new Map(); + return data; + } +} diff --git a/lib/models/base_response.dart b/lib/models/base_response.dart new file mode 100644 index 0000000..3bf97d5 --- /dev/null +++ b/lib/models/base_response.dart @@ -0,0 +1,31 @@ +class BaseResponse { + int? code; + dynamic data; + bool? fail; + String? key; + String? msg; + bool? success; + + BaseResponse( + {this.code, this.data, this.fail, this.key, this.msg, this.success}); + + BaseResponse.fromJson(Map json) { + code = json['code']; + fail = json['fail']; + key = json['key']; + data = json['data']; + msg = json['msg']; + success = json['success']; + } + + Map toJson() { + final Map data = new Map(); + data['code'] = code; + data['fail'] = fail; + data['data'] = data; + data['key'] = key; + data['msg'] = msg; + data['success'] = success; + return data; + } +} diff --git a/lib/models/mine_about.model.dart b/lib/models/mine_about.model.dart new file mode 100644 index 0000000..d559251 --- /dev/null +++ b/lib/models/mine_about.model.dart @@ -0,0 +1,4 @@ +class MineAboutModel { + late String title; + MineAboutModel({required this.title}); +} diff --git a/lib/models/user_info.model.dart b/lib/models/user_info.model.dart new file mode 100644 index 0000000..45a9eec --- /dev/null +++ b/lib/models/user_info.model.dart @@ -0,0 +1,230 @@ +class UserInfoModel { + String? userId; + int? userType; + String? nickname; + bool? isInternal; + String? avatar; + String? avatarUrl; + String? avatarThumbUrl; + String? avatarMiddleThumbUrl; + List? mediumList; + List? avatarRespList; + int? gender; + String? birthday; + int? age; + String? country; + String? pkgName; + bool? isAnswer; + int? availableCoins; + int? auditStatus; + bool? isShowReviewSupplementTips; + List? tagsList; + List? tagDetails; + String? rongcloudToken; + bool? isRecharge; + bool? isVip; + int? level; + int? followNum; + int? praiseNum; + bool? isBlock; + bool? isSwitchNotDisturbIm; + bool? isSwitchNotDisturbCall; + bool? isHavePassword; + bool? isReview; + bool? isMultiple; + String? registerPkgName; + String? registerCountry; + String? loginPkgName; + int? giftWallAction; + + UserInfoModel({ + this.userId, + this.userType, + this.nickname, + this.isInternal, + this.avatar, + this.avatarUrl, + this.avatarThumbUrl, + this.avatarMiddleThumbUrl, + this.mediumList, + this.avatarRespList, + this.gender, + this.birthday, + this.age, + this.country, + this.pkgName, + this.isAnswer, + this.availableCoins, + this.auditStatus, + this.isShowReviewSupplementTips, + this.tagsList, + this.tagDetails, + this.rongcloudToken, + this.isRecharge, + this.isVip, + this.level, + this.followNum, + this.praiseNum, + this.isBlock, + this.isSwitchNotDisturbIm, + this.isSwitchNotDisturbCall, + this.isHavePassword, + this.isReview, + this.isMultiple, + this.registerPkgName, + this.registerCountry, + this.loginPkgName, + this.giftWallAction, + }); + + UserInfoModel.fromJson(Map json) { + userId = json['userId']; + userType = json['userType']; + nickname = json['nickname']; + isInternal = json['isInternal']; + avatar = json['avatar']; + avatarUrl = json['avatarUrl']; + avatarThumbUrl = json['avatarThumbUrl']; + avatarMiddleThumbUrl = json['avatarMiddleThumbUrl']; + + if (json['avatarRespList'] != null) { + avatarRespList = []; + json['avatarRespList'].forEach((v) { + avatarRespList!.add(AvatarRespList.fromJson(v)); + }); + } + gender = json['gender']; + birthday = json['birthday']; + age = json['age']; + country = json['country']; + pkgName = json['pkgName']; + + isAnswer = json['isAnswer']; + availableCoins = json['availableCoins']; + auditStatus = json['auditStatus']; + isShowReviewSupplementTips = json['isShowReviewSupplementTips']; + if (json['tagsList'] != null) { + tagsList = []; + json['tagsList'].forEach((v) { + tagsList!.add(v); + }); + } + if (json['tagDetails'] != null) { + tagDetails = []; + json['tagDetails'].forEach((v) { + tagDetails!.add(TagDetails.fromJson(v)); + }); + } + rongcloudToken = json['rongcloudToken']; + isRecharge = json['isRecharge']; + isVip = json['isVip']; + level = json['level']; + followNum = json['followNum']; + praiseNum = json['praiseNum']; + isBlock = json['isBlock']; + isSwitchNotDisturbIm = json['isSwitchNotDisturbIm']; + isSwitchNotDisturbCall = json['isSwitchNotDisturbCall']; + isHavePassword = json['isHavePassword']; + isReview = json['isReview']; + isMultiple = json['isMultiple']; + registerPkgName = json['registerPkgName']; + registerCountry = json['registerCountry']; + loginPkgName = json['loginPkgName']; + giftWallAction = json['giftWallAction']; + } + + Map toJson() { + final Map data = Map(); + data['userId'] = userId; + data['userType'] = userType; + data['nickname'] = nickname; + data['isInternal'] = isInternal; + data['avatar'] = avatar; + data['avatarUrl'] = avatarUrl; + data['avatarThumbUrl'] = avatarThumbUrl; + data['avatarMiddleThumbUrl'] = avatarMiddleThumbUrl; + if (this.avatarRespList != null) { + data['avatarRespList'] = avatarRespList!.map((v) => v.toJson()).toList(); + } + data['gender'] = gender; + data['birthday'] = birthday; + data['age'] = age; + data['country'] = country; + data['pkgName'] = pkgName; + + data['isAnswer'] = isAnswer; + data['availableCoins'] = availableCoins; + data['auditStatus'] = auditStatus; + data['isShowReviewSupplementTips'] = isShowReviewSupplementTips; + if (this.tagsList != null) { + data['tagsList'] = tagsList!.map((v) => v).toList(); + } + if (this.tagDetails != null) { + data['tagDetails'] = tagDetails!.map((v) => v.toJson()).toList(); + } + data['rongcloudToken'] = rongcloudToken; + data['isRecharge'] = isRecharge; + data['isVip'] = isVip; + data['level'] = level; + data['followNum'] = followNum; + data['praiseNum'] = praiseNum; + data['isBlock'] = isBlock; + data['isSwitchNotDisturbIm'] = isSwitchNotDisturbIm; + data['isSwitchNotDisturbCall'] = isSwitchNotDisturbCall; + data['isHavePassword'] = isHavePassword; + data['isReview'] = isReview; + data['isMultiple'] = isMultiple; + data['registerPkgName'] = registerPkgName; + data['registerCountry'] = registerCountry; + data['loginPkgName'] = loginPkgName; + data['giftWallAction'] = giftWallAction; + return data; + } +} + +class AvatarRespList { + String? mediaPath; + String? mediaUrl; + String? middleThumbUrl; + String? thumbUrl; + + AvatarRespList({this.mediaPath, mediaUrl, middleThumbUrl, thumbUrl}); + + AvatarRespList.fromJson(Map json) { + mediaPath = json['mediaPath']; + mediaUrl = json['mediaUrl']; + middleThumbUrl = json['middleThumbUrl']; + thumbUrl = json['thumbUrl']; + } + + Map toJson() { + final Map data = Map(); + data['mediaPath'] = mediaPath; + data['mediaUrl'] = mediaUrl; + data['middleThumbUrl'] = middleThumbUrl; + data['thumbUrl'] = thumbUrl; + return data; + } +} + +class TagDetails { + String? tag; + String? tagTip; + String? tagColor; + + TagDetails({this.tag, tagTip, tagColor}); + + TagDetails.fromJson(Map json) { + tag = json['tag']; + tagTip = json['tagTip']; + tagColor = json['tagColor']; + } + + Map toJson() { + final Map data = Map(); + data['tag'] = tag; + data['tagTip'] = tagTip; + data['tagColor'] = tagColor; + return data; + } +} diff --git a/lib/screens/home/home.dart b/lib/screens/home/home.dart new file mode 100644 index 0000000..0ff65ec --- /dev/null +++ b/lib/screens/home/home.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} diff --git a/lib/screens/landing/zt_landing.dart b/lib/screens/landing/zt_landing.dart new file mode 100644 index 0000000..67d1f38 --- /dev/null +++ b/lib/screens/landing/zt_landing.dart @@ -0,0 +1,73 @@ +// import 'dart:io'; + +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import '../../models/app_bottom_nav_item.dart'; +import '../../services/app_info.service.dart'; +import '../../util/util.dart'; + +class LandingPage extends StatefulWidget { + LandingPage({Key? key}) : super(key: key); + + @override + _LandingPageState createState() => _LandingPageState(); +} + +class _LandingPageState extends State { + int _selectedLanding = 0; + + List bottomNavItems = []; + List pages = []; + + @override + Widget build(BuildContext context) { + // ScreenUtil.init( + // BoxConstraints( + // maxWidth: MediaQuery.of(context).size.width, + // maxHeight: MediaQuery.of(context).size.height), + // designSize: const Size(414, 896), + // orientation: Orientation.portrait, + // context: context, + // ); + List roleWithBottomNavItems = + AppInfoService.to.bottomNavItems!; + bottomNavItems = roleWithBottomNavItems + .map((e) => BottomNavigationBarItem( + icon: Image.asset( + e.icon!, + height: ScreenAdaper.width(30), + width: ScreenAdaper.width(30), + ), + activeIcon: Image.asset( + e.activeIcon!, + height: ScreenAdaper.width(30), + width: ScreenAdaper.width(30), + ), + label: e.label)) + .toList(); + pages = roleWithBottomNavItems.map((e) => e.page!).toList(); + return Scaffold( + bottomNavigationBar: BottomNavigationBar( + iconSize: ScreenAdaper.sp(25), + type: BottomNavigationBarType.fixed, + items: bottomNavItems, + showSelectedLabels: false, + showUnselectedLabels: false, + currentIndex: _selectedLanding, + onTap: (landing) { + _onItemTapped(landing); + }, + ), + body: pages[_selectedLanding], + ); + } + + void _onItemTapped(int landing) { + if (landing != _selectedLanding) { + setState(() { + _selectedLanding = landing; + }); + } + } +} diff --git a/lib/screens/login/login.controller.dart b/lib/screens/login/login.controller.dart new file mode 100644 index 0000000..37a03f2 --- /dev/null +++ b/lib/screens/login/login.controller.dart @@ -0,0 +1,37 @@ +import 'package:flutter/widgets.dart'; +import 'package:get/get.dart'; +import 'package:sk_base_mobile/config.dart'; +import '../../constants/enum.dart'; +import '../../store/auth.store.dart'; +import '../../util/util.dart'; + +class LoginController extends GetxController { + final isAgreeTerm = RxBool(false); + + Future fastLogin() async { + await confirmAgreement().then((value) async { + if (value != null) { + await AuthStore.to.login(LoginEnum.fastLogin); + } + }); + } + + Future confirmAgreement() async { + // if (!isAgreeTerm.value) { + // return Get.defaultDialog( + // title: '', + // content: ConfirmAgreement(), + // titlePadding: const EdgeInsets.all(0)); + // } else { + // return Future(() => true); + // } + } + + Future onPrivacyPolicyTap() async { + // launchUrl(Uri.parse(GloablConfig.PRIVACY_POLICY)); + } + + Future onTermTap() async { + // launchUrl(Uri.parse(GloablConfig.TERM_OF_USER)); + } +} diff --git a/lib/screens/login/login.dart b/lib/screens/login/login.dart new file mode 100644 index 0000000..796bd60 --- /dev/null +++ b/lib/screens/login/login.dart @@ -0,0 +1,198 @@ +import 'package:flutter/material.dart'; +import 'package:sk_base_mobile/app_theme.dart'; +import 'package:sk_base_mobile/util/screen_adaper_util.dart'; + +class LoginScreen extends StatelessWidget { + LoginScreen({super.key}); + final formKey = GlobalKey(); + late BuildContext theContext; + bool loading = false; + String? username; + String? password; + @override + Widget build(BuildContext context) { + return Scaffold(body: SafeArea(child: buildBody())); + } + + buildBody() { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + // 触摸收起键盘 + }, + child: Padding( + padding: EdgeInsets.fromLTRB(0, 0, 10, 30), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Logo(size: 120), + SizedBox(height: 30), + buildForm(), + SizedBox(height: 30), + ], + ), + ), + buildGoRegister(), + buildNotice(), + ], + ), + ))); + } + + Widget buildNotice() { + return Padding( + padding: EdgeInsets.fromLTRB(50, 5, 50, 5), + child: Text( + 'If you have registered as a PLAYER, COACH, MANAGER or REFEREE, please use your login details provided.', + textAlign: TextAlign.center, + style: TextStyle(fontWeight: FontWeight.bold))); + } + + Widget buildForm() { + final children = [ + buildUserNameInput(), + SizedBox( + height: 15, + ), + buildPasswordInput(), + SizedBox( + height: 12, + ), + buildForgotPassword(), + SizedBox( + height: 12, + ), + buildSubmitButton(), + + /* SizedBox( + height: 12, + ), + buildRegistry() */ + ]; + + final child = Column( + mainAxisAlignment: MainAxisAlignment.start, + children: children, + ); + + return Form( + key: formKey, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 0, horizontal: 50), + child: child, + )); + } + + Widget buildGoRegister() => Container( + child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Text('Don\'t have an account?'), + SizedBox(width: 5), + GestureDetector( + onTap: () {}, + child: Text('Create', + style: TextStyle( + color: AppTheme.primaryColor, + decoration: TextDecoration.underline, + ))), + ]), + ); + + Widget buildSubmitButton() { + final color = AppTheme.primaryColor; + + // final button = RaisedButton( + // shape: StadiumBorder(), + // child: loading + // ? SizedBox( + // child: CircularProgressIndicator( + // color: AppTheme.primaryColorDark, + // ), + // height: 18, + // width: 18, + // ) + // : Text('Sign In'), + // onPressed: () { + // _submit(); + // }, + // color: color, + // /* elevation: 20, */ + // padding: EdgeInsets.all(12), + // ); + + // final child = Expanded( + // child: button, + // ); + + return Row( + children: [], + ); + } + + Widget buildUserNameInput() { + return TextFormField( + initialValue: username, + decoration: InputDecoration( + labelText: 'Email / Reg ID', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(ScreenAdaper.sp(10))), + fillColor: Color(0xFFF8F8F8), + ), + onChanged: (value) { + this.username = value; + }, + validator: (String? value) { + if (value == null || value == '') { + return 'Email / Reg ID is required'; + } else { + return null; + } + }, + ); + } + + Widget buildPasswordInput() { + return TextFormField( + initialValue: password, + decoration: InputDecoration( + labelText: 'Password', + /* border: OutlineInputBorder(), */ + fillColor: Color(0xFFF8F8F8), + ), + obscureText: true, + onChanged: (value) { + this.password = value; + }, + validator: (String? value) { + return (value ?? '').length >= 6 ? null : 'Invalid password'; + }, + ); + } + + Future _submit() async { + if (!formKey.currentState!.validate()) { + return; + } + + return; + } + + Widget buildForgotPassword() { + return GestureDetector( + onTap: () {}, + child: Container( + alignment: Alignment.centerRight, + child: Text( + 'Forgot Password?', + style: TextStyle( + color: Colors.grey, + decoration: TextDecoration.underline, + ), + )), + ); + } +} diff --git a/lib/screens/mine/mine.controller.dart b/lib/screens/mine/mine.controller.dart new file mode 100644 index 0000000..e1aa51a --- /dev/null +++ b/lib/screens/mine/mine.controller.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:sk_base_mobile/models/mine_about.model.dart'; +import 'package:sk_base_mobile/store/auth.store.dart'; + +class MineController extends GetxController { + final selectedTabIndex = 0.obs; + TabController? tabController; + final List mineTabs = ['ticket', 'block', 'about', 'setting']; + final List aboutList = [ + // MineAboutModel(title: 'Version'), + // MineAboutModel(title: 'Terms and Conditons'), + // MineAboutModel(title: 'Privacy Policy'), + // MineAboutModel(title: 'Rate Us'), + ]; + + @override + void onInit() { + // AuthStore.to.getUserInfo(); + + super.onInit(); + } +} diff --git a/lib/screens/mine/mine.dart b/lib/screens/mine/mine.dart new file mode 100644 index 0000000..88f87dc --- /dev/null +++ b/lib/screens/mine/mine.dart @@ -0,0 +1,213 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:sk_base_mobile/screens/mine/mine.controller.dart'; +// import 'package:sk_base_mobile/screens/mine/mine_about.dart'; +// import 'package:sk_base_mobile/screens/mine/mine_block.dart'; +// import 'package:sk_base_mobile/screens/mine/mine_mytickets.dart'; +// import 'package:sk_base_mobile/screens/mine/mine_settings.dart'; +import 'package:sk_base_mobile/services/service.dart'; +import 'package:sk_base_mobile/store/auth.store.dart'; +import 'package:sk_base_mobile/util/common.util.dart'; +import 'package:sk_base_mobile/util/screen_adaper_util.dart'; +import 'package:sk_base_mobile/widgets/want_keep_alive.dart'; +import 'package:sk_base_mobile/widgets/my_avatar.dart'; +import 'package:sk_base_mobile/app_theme.dart'; +import 'package:sk_base_mobile/constants/router.dart'; +import '../../constants/constants.dart'; + +class MinePage extends StatefulWidget { + MinePage({super.key}); + + @override + State createState() => _MinePageState(); +} + +class _MinePageState extends State + with SingleTickerProviderStateMixin { + final _controller = Get.put(MineController()); + + @override + void initState() { + super.initState(); + _controller.tabController ??= TabController( + initialIndex: _controller.selectedTabIndex.value, + length: 4, + vsync: this); + } + + @override + Widget build(BuildContext context) { + return _buildBody(); + } + + Widget _buildBody() { + return Column(mainAxisSize: MainAxisSize.max, children: [ + Container( + height: ScreenAdaper.height(360), + width: ScreenAdaper.screenWidth(), + decoration: const BoxDecoration( + image: DecorationImage( + fit: BoxFit.cover, + image: AssetImage('assets/images/mine_bg.png'))), + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: ScreenAdaper.width(20), + vertical: ScreenAdaper.height(20)), + child: Column(children: [ + SizedBox( + height: ScreenAdaper.height(30), + ), + Row( + children: [ + const Spacer(), + Container( + height: ScreenAdaper.width(40), + width: ScreenAdaper.width(40), + padding: EdgeInsets.all(ScreenAdaper.width(2)), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(ScreenAdaper.sp(40)), + color: const Color(0xFF000000).withOpacity(0.3)), + child: const SizedBox(), + ) + ], + ), + SizedBox( + height: ScreenAdaper.height(120), + ), + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Obx(() => Text( + AuthStore.to.userInfo.value.nickname ?? '', + style: TextStyle( + fontSize: ScreenAdaper.sp(20), + fontWeight: FontWeight.w400), + )), + SizedBox( + width: ScreenAdaper.width(3), + ), + InkWell( + onTap: () { + Get.toNamed(RouteConfig.userinfo); + }, + child: Image( + image: + const AssetImage('assets/images/edit_icon.png'), + height: ScreenAdaper.width(20), + ), + ) + ], + ), + SizedBox( + height: ScreenAdaper.height(15), + ), + Text(StorageService.to.getString(CacheKeys.deviceUUID) ?? + ''), + Row( + children: [ + SizedBox( + width: ScreenAdaper.width(210), + child: Text( + 'ID: ${AuthStore.to.userInfo.value.userId}', + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: TextStyle( + fontSize: ScreenAdaper.sp(16), + color: Colors.grey[500]), + ), + ), + InkWell( + onTap: () {}, + child: Container( + alignment: Alignment.topCenter, + width: ScreenAdaper.width(50), + height: ScreenAdaper.height(30), + padding: EdgeInsets.symmetric( + horizontal: ScreenAdaper.width(5)), + decoration: BoxDecoration( + color: const Color(0xFF454545), + borderRadius: BorderRadius.circular(5)), + child: Text('copy', + style: TextStyle( + color: AppTheme.white, + fontSize: ScreenAdaper.sp(16)))), + ) + ], + ) + ], + )), + MyAvatarWidget() + ], + ) + ]), + ), + ), + Expanded( + child: DefaultTabController( + length: 4, + initialIndex: _controller.selectedTabIndex.value, + child: Scaffold( + backgroundColor: AppTheme.white, + appBar: AppBar( + backgroundColor: AppTheme.white, + elevation: 0, + automaticallyImplyLeading: false, + flexibleSpace: _buildTabBar(), + ), + body: _buildTabView()))) + ]); + } + + Widget _buildTabBar() { + final tabs = _controller.mineTabs + .asMap() + .map((index, item) { + return MapEntry( + index, + Obx( + () => Tab( + child: Image( + image: AssetImage( + 'assets/images/$item${_controller.selectedTabIndex.value == index ? '_active' : ''}.png'))), + )); + }) + .values + .toList(); + + return Container( + margin: EdgeInsets.only(top: ScreenAdaper.height(20)), + padding: EdgeInsets.symmetric(vertical: ScreenAdaper.height(10)), + decoration: const BoxDecoration( + border: Border.symmetric( + horizontal: BorderSide(color: Color(0xFFCCCCCC)))), + child: TabBar( + controller: _controller.tabController, + tabs: tabs, + indicator: const BoxDecoration(), + onTap: (index) { + _controller.selectedTabIndex.value = index; + }, /* */ + ), + ); + } + + Widget _buildTabView() { + return TabBarView( + controller: _controller.tabController, + physics: const NeverScrollableScrollPhysics(), + children: [ + SizedBox(), + SizedBox(), + SizedBox(), + SizedBox(), + ], + ); + } +} diff --git a/lib/screens/mine/useinfo/userinfo.controller.dart b/lib/screens/mine/useinfo/userinfo.controller.dart new file mode 100644 index 0000000..fa24420 --- /dev/null +++ b/lib/screens/mine/useinfo/userinfo.controller.dart @@ -0,0 +1,28 @@ +import 'package:flutter/cupertino.dart'; +import 'package:get/get.dart'; +import 'package:sk_base_mobile/models/user_info.model.dart'; +import 'package:sk_base_mobile/store/auth.store.dart'; +import 'package:sk_base_mobile/apis/api.dart' as Api; + +class UserInfoController extends GetxController { + final nickNameController = TextEditingController(text: ''); + final countryController = TextEditingController(text: ''); + final birthdayController = TextEditingController(); + + @override + void onReady() async { + nickNameController.text = AuthStore.to.userInfo.value.nickname ?? ''; + birthdayController.text = AuthStore.to.userInfo.value.birthday ?? ''; + countryController.text = AuthStore.to.userInfo.value.country ?? ''; + super.onReady(); + } + + Future saveUserInfo() async { + Map data = { + 'nickname': nickNameController.text, + 'birthday': birthdayController.text, + 'country': countryController.text, + }; + await AuthStore.to.saveUserInfo(data); + } +} diff --git a/lib/screens/mine/useinfo/userinfo.dart b/lib/screens/mine/useinfo/userinfo.dart new file mode 100644 index 0000000..97b1212 --- /dev/null +++ b/lib/screens/mine/useinfo/userinfo.dart @@ -0,0 +1,183 @@ +import 'package:date_format/date_format.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:sk_base_mobile/constants/data.dart'; +import 'package:sk_base_mobile/util/screen_adaper_util.dart'; +import 'package:sk_base_mobile/widgets/my_avatar.dart'; + +import 'userinfo.controller.dart'; + +class UserInfoPage extends StatelessWidget { + final _controller = Get.put(UserInfoController()); + UserInfoPage({super.key}); + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + elevation: 0, + actions: [ + TextButton( + onPressed: () { + _controller.saveUserInfo(); + }, + child: Text( + 'Save', + style: TextStyle( + color: const Color(0xFFB0F320), + fontSize: ScreenAdaper.sp(18)), + )), + SizedBox( + width: ScreenAdaper.width(5), + ) + ], + backgroundColor: Colors.transparent), + body: _buildBody(), + )); + } + + Widget _buildBody() { + return Column( + children: [ + SizedBox( + height: ScreenAdaper.height(50), + ), + Center( + child: MyAvatarWidget(), + ), + TextFormField( + controller: _controller.nickNameController, + cursorColor: const Color.fromARGB(255, 87, 86, 86), + style: TextStyle(fontSize: ScreenAdaper.sp(18), color: Colors.black), + decoration: InputDecoration( + contentPadding: EdgeInsets.fromLTRB( + ScreenAdaper.width(12), 0, ScreenAdaper.width(12), 0), + labelText: "Nick Name", + labelStyle: TextStyle( + color: const Color.fromARGB(255, 136, 136, 136), + fontSize: ScreenAdaper.sp(18)), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB(153, 191, 190, 190), + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB(153, 191, 190, 190), + ), + ), + ), + ), + SizedBox( + height: ScreenAdaper.height(15), + ), + TextFormField( + controller: _controller.birthdayController, + decoration: InputDecoration( + contentPadding: EdgeInsets.fromLTRB( + ScreenAdaper.width(12), 0, ScreenAdaper.width(12), 0), + labelText: "Date of birth", + labelStyle: TextStyle( + color: const Color.fromARGB(255, 136, 136, 136), + fontSize: ScreenAdaper.sp(18)), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB(153, 191, 190, 190), + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB(153, 191, 190, 190), + ), + ), + ), + onTap: () async { + await showCupertinoModalPopup( + context: Get.context!, + builder: (context) => Container( + color: Colors.white, + height: 300, + child: CupertinoDatePicker( + initialDateTime: DateTime.parse( + _controller.birthdayController.text), + minimumDate: DateTime(1900), + maximumDate: DateTime.now() + .subtract(const Duration(days: 18 * 365)), + minimumYear: DateTime(1900).year, + maximumYear: DateTime.now() + .subtract(const Duration(days: 18 * 365)) + .year, + mode: CupertinoDatePickerMode.date, + onDateTimeChanged: (pickeddate) { + _controller.birthdayController.text = + formatDate(pickeddate, [ + yyyy, + '-', + mm, + '-', + dd, + ]); + }), + )); + }, + style: + TextStyle(fontSize: ScreenAdaper.sp(18), color: Colors.black), + cursorColor: const Color.fromARGB(255, 87, 86, 86)), + SizedBox( + height: ScreenAdaper.height(15), + ), + TextFormField( + controller: _controller.countryController, + decoration: InputDecoration( + contentPadding: EdgeInsets.fromLTRB( + ScreenAdaper.width(12), 0, ScreenAdaper.width(12), 0), + labelText: "Country", + labelStyle: TextStyle( + color: const Color.fromARGB(255, 136, 136, 136), + fontSize: ScreenAdaper.sp(18)), + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB(153, 191, 190, 190), + ), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB(153, 191, 190, 190), + ), + ), + ), + onTap: () async { + await showCupertinoModalPopup( + context: Get.context!, + builder: (context) => Container( + color: Colors.white, + height: 300, + child: CupertinoPicker( + itemExtent: 50, + onSelectedItemChanged: (index) { + _controller.countryController.text = + Data.countryCodes[index]; + }, + children: Data.countryCodes + .map((e) => Container( + height: ScreenAdaper.height(50), + alignment: Alignment.center, + child: Text( + e, + style: TextStyle( + fontSize: ScreenAdaper.sp(30)), + ), + )) + .toList(), + ))); + }, + style: + TextStyle(fontSize: ScreenAdaper.sp(18), color: Colors.black), + cursorColor: const Color.fromARGB(255, 87, 86, 86)) + ], + ); + } +} diff --git a/lib/services/app_info.service.dart b/lib/services/app_info.service.dart new file mode 100644 index 0000000..d9958e5 --- /dev/null +++ b/lib/services/app_info.service.dart @@ -0,0 +1,144 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:get/get.dart'; +import 'package:package_info/package_info.dart'; +import 'package:sk_base_mobile/models/app_bottom_nav_item.dart'; +import 'package:sk_base_mobile/models/app_config.dart'; +import 'package:sk_base_mobile/screens/home/home.dart'; +import 'package:sk_base_mobile/apis/api.dart' as Api; +import 'package:sk_base_mobile/services/service.dart'; +import 'package:sk_base_mobile/store/auth.store.dart'; +import 'package:sk_base_mobile/util/convert.dart'; +import 'package:sk_base_mobile/util/logger_util.dart'; +import 'dart:ui' as ui; +import 'package:sk_base_mobile/config.dart'; +import '../constants/constants.dart'; +import '../screens/mine/mine.dart'; + +class AppInfoService extends GetxService { + static AppInfoService get to => Get.find(); + final versionNumber = RxString(''); + late AppConfig appConfig; + final scale = RxDouble(1.0); + final isLarge = RxBool(false); + final isCameraing = RxBool(false); + List? bottomNavItems = [ + AppBottomNavItem( + icon: 'assets/images/landing_icon_bottom_0.png', + activeIcon: 'assets/images/landing_icon_bottom_active_0.png', + label: 'homepage', + page: const HomePage()), + AppBottomNavItem( + icon: 'assets/images/landing_icon_bottom_3.png', + activeIcon: 'assets/images/landing_icon_bottom_active_3.png', + label: 'mine', + page: MinePage()), + ]; + Future init() async { + LoggerUtil() + .info("[service-appInfo] Register app-related information service"); + + try { + await Future.wait( + [getDeviceInfo(), getPackageInfo(), getAppConfig(), getossPolicy()]); + requestPermission(); + } catch (e) { + LoggerUtil().error(e); + } + return this; + } + + Future setIsFirstInstall() async { + await StorageService.to + .setBool(CacheKeys.isFirstInstall, true, isWithUser: false); + } + + bool checkIsFirstInstall() { + bool? isFirstInstallCache = + StorageService.to.getBool(CacheKeys.isFirstInstall, isWithUser: false); + return isFirstInstallCache == null || !isFirstInstallCache; + } + + Future getDeviceInfo() async { + // DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); + // if (Platform.isIOS) { + // iosDeviceInfo = await deviceInfo.iosInfo; + // if (iosDeviceInfo != null) { + // await StorageService.to.setString( + // CacheKeys.deviceUUID, iosDeviceInfo!.identifierForVendor!, + // isWithUser: false); + // await StorageService.to.setString( + // CacheKeys.deviceModel, iosDeviceInfo!.name, + // isWithUser: false); + // } + // } else { + // androidDeviceInfo = await deviceInfo.androidInfo; + // await StorageService.to.setString( + // CacheKeys.deviceUUID, GloablConfig.DEVICE_UUID, + // isWithUser: false); + // await StorageService.to.setString( + // CacheKeys.deviceModel, GloablConfig.DEVICE_MODEL, + // isWithUser: false); + // } + } + + Future getPackageInfo() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + versionNumber.value = packageInfo.version; + } + + Future getAppConfig() async { + if (StorageService.to.getString(CacheKeys.token, isWithUser: false) != + null) { + final response = await Api.getAppConfig(); + if (response.data != null) { + appConfig = AppConfig.fromJson(response.data['data']); + await StorageService.to.setString( + CacheKeys.appConfig, jsonEncode(appConfig.items!), + isWithUser: false); + if (appConfig.ver != null) { + await StorageService.to + .setString(CacheKeys.ver, appConfig.ver!, isWithUser: false); + } + } + } + } + + // need token + Future getossPolicy() async { + // if (StorageService.to.getString(CacheKeys.token, isWithUser: false) != + // null) { + // final response = await Api.getOssPolicy(); + // if (response.data != null) { + // ossPolicy = OssPolicy.fromJson(response.data['data']); + // } + // } + } + + T getConfigByCode(String code) { + List items = appConfig.items!; + dynamic config = items.firstWhereOrNull((element) => element.name == code); + if (config != null) { + return config.data as T; + } + return '' as T; + } + + void changeTextScale(bool? value) { + if (value ?? false) { + scale(1.2); + } else { + scale(1.0); + } + isLarge.value = value ?? false; + } + + Future requestPermission() async { + // final status = await AppTrackingTransparency.trackingAuthorizationStatus; + // if (status != TrackingStatus.authorized) { + // await Future.delayed(const Duration(seconds: 2)); + // await AppTrackingTransparency.requestTrackingAuthorization(); + // } + } +} diff --git a/lib/services/dio.service.dart b/lib/services/dio.service.dart new file mode 100644 index 0000000..60fe18c --- /dev/null +++ b/lib/services/dio.service.dart @@ -0,0 +1,173 @@ +import 'dart:convert'; + +import 'package:get/get.dart' as Get; +import 'package:dio/dio.dart'; +import 'package:sk_base_mobile/util/logger_util.dart'; +import 'package:sk_base_mobile/config.dart'; +import 'package:sk_base_mobile/services/storage.service.dart'; +import 'package:sk_base_mobile/store/auth.store.dart'; +import 'package:sk_base_mobile/util/snack_bar.util.dart'; + +import '../constants/constants.dart'; + +class DioService extends Get.GetxService { + static DioService get to => Get.Get.find(); + static Dio get dio => _dio; + static late Dio _dio; + List whiteList = [Urls.googleTranslate]; + BaseOptions dioBaseOptions = BaseOptions( + connectTimeout: const Duration(minutes: 10), + baseUrl: '${GloablConfig.BASE_URL}', + followRedirects: true); + + late CancelToken cancelToken; + + /// Initialize the dio instance + Future init() async { + _dio = Dio(dioBaseOptions); + _dio.interceptors.add(InterceptorsWrapper( + onRequest: onRequest, onResponse: onResponse, onError: onError)); + cancelToken = CancelToken(); + return this; + } + + void onError(DioException e, ErrorInterceptorHandler handler) async { + if (whiteList.contains(e.requestOptions.path)) { + await SnackBarUtil().error(e.message); + return handler.next(e); + } + if (GloablConfig.DEBUG) { + LoggerUtil().info( + "[Service-dio] Error found on ${e.requestOptions.method} ${e.requestOptions.uri}"); + } + if (e.type == DioExceptionType.connectionTimeout) { + // It occurs when url is opened timeout. + await SnackBarUtil().error( + 'The server is busy, please try again.', + ); + } else if (e.type == DioExceptionType.sendTimeout) { + // It occurs when url is sent timeout. + // await SnackBarUtil().error( + // 'The server is busy, please try again.', + // ); + } else if (e.type == DioExceptionType.receiveTimeout) { + //It occurs when receiving timeout + // await SnackBarUtil().error( + // 'The server is busy, please try again.', + // ); + } else if (e.type == DioErrorType.badResponse) { + // When the server response, but with a incorrect status, such as 404, 503... + if (e.response?.statusCode == 400) { + await SnackBarUtil().error( + e.response?.data['message'], + ); + } else if (e.response?.statusCode == 401) { + await SnackBarUtil().error( + 'Your role at this season has been updated. Please log in again.', + ); + // dio.lock(); + LoggerUtil().error('[Service-dio] logout:${e.response}'); + await AuthStore().logout(force: true); + } else if (e.response?.statusCode == 403) { + await SnackBarUtil().error( + '${e.response?.data['message']}.', + ); + // await AuthStore().logout(force: true); + } else if (e.response?.statusCode == 409) { + await SnackBarUtil().error(e.response?.data['message']); + } else if (e.response?.statusCode == 500) { + await SnackBarUtil() + .error('The server is busy, please try again later'); + } else if (e.response?.statusCode == 404) { + LoggerUtil().error('[Service-dio] logout:${e.response}'); + // await AuthStore().logout(force: true); + } else if (e.response?.statusCode == 422) { + await SnackBarUtil().error(e.response?.data['message']); + } + } else if (e.type == DioErrorType.cancel) { + // When the request is cancelled, dio will throw a error with this type. + LoggerUtil().error("[Service-dio] 请求取消"); + } else { + //DEFAULT Default error type, Some other Error. In this case, you can read the DioError.error if it is not null. + LoggerUtil().error("[Service-dio] 未知错误:$e"); + if ((e.error?.toString() ?? '') + .toString() + .contains("HandshakeException")) { + // Just a network failure + } else { + await SnackBarUtil().error(e.error.toString()); + // AuthStore().logout(force: true); + } + } + return handler.next(e); + } + + whiteListFilter(String url) => url.endsWith('_allow_anonymous=true'); + + void onRequest(RequestOptions options, RequestInterceptorHandler handler) { + if (!whiteList.contains(options.path)) { + String? token = + StorageService.to.getString(CacheKeys.token, isWithUser: false); + if (options.headers['Authorization'] == null && token != null) { + options.headers["Authorization"] = "Bearer$token"; + } + options.headers['device-id'] = StorageService.to.getString( + CacheKeys.deviceUUID, + isWithUser: false); // 设备id或者udid,保证当前设备唯一值。 + options.headers["platform"] = "iOS"; + options.headers['model'] = StorageService.to + .getString(CacheKeys.deviceModel, isWithUser: false); // 设备型号 + } + if (GloablConfig.DEBUG && (options.data is! FormData)) { + LoggerUtil().info('[Service-dio] url: ${options.path}' + + ', params: ${jsonEncode(options.queryParameters)}' + + ', body: ${jsonEncode(options.data)}, Header:${jsonEncode(options.headers)}'); + } + + handler.next(options); + } + + void onResponse(Response response, ResponseInterceptorHandler handler) async { + /* LoggerUtil().info('[Service-dio] ${response.data}'); */ + if (whiteList.contains(response.requestOptions.path)) { + handler.next(response); + return; + } + if (response.data != null) { + try { + dynamic responseData = response.data; + if (response.data is String) { + responseData = jsonDecode(response.data); + } + switch (responseData['code']) { + case 0: + handler.next(response); + return; + // 其他设备登录 + case 10010304: + await AuthStore().logout(force: true); + await SnackBarUtil() + .error('Other devices have logged in, please log in again.'); + break; + case 100103: + case 10010303: + await AuthStore().logout(force: true); + await SnackBarUtil() + .error('Login has timed out, please log in again.'); + break; + case 10010301: + await AuthStore().logout(force: true); + await SnackBarUtil().error('Token can not empty'); + break; + default: + await SnackBarUtil() + .error('${responseData['key']}: ${responseData['msg']}'); + break; + } + } catch (e) { + printError(info: e.toString()); + } + } + handler.next(response); + } +} diff --git a/lib/services/service.dart b/lib/services/service.dart new file mode 100644 index 0000000..37f5ea6 --- /dev/null +++ b/lib/services/service.dart @@ -0,0 +1,5 @@ +library services; + +export 'dio.service.dart'; +export 'app_info.service.dart'; +export 'storage.service.dart'; diff --git a/lib/services/storage.service.dart b/lib/services/storage.service.dart new file mode 100644 index 0000000..8f61198 --- /dev/null +++ b/lib/services/storage.service.dart @@ -0,0 +1,92 @@ +import 'package:get/get.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:sk_base_mobile/store/auth.store.dart'; + +class StorageService extends GetxService { + static StorageService get to => Get.find(); + late final SharedPreferences _prefs; + + Future init() async { + _prefs = await SharedPreferences.getInstance(); + return this; + } + + Future setString(String key, String value, + {bool isWithUser = true}) async { + String storeKey = key; + if (isWithUser) { + storeKey = '${AuthStore.to.userInfo.value.userId}_$key'; + } + return await _prefs.setString(storeKey, value); + } + + Future setBool(String key, bool value, {bool isWithUser = true}) async { + String storeKey = key; + if (isWithUser) { + storeKey = '${AuthStore.to.userInfo.value.userId}_$key'; + } + return await _prefs.setBool(storeKey, value); + } + + Future setInt(String key, int value, {bool isWithUser = true}) async { + String storeKey = key; + if (isWithUser) { + storeKey = '${AuthStore.to.userInfo.value.userId}_$key'; + } + return await _prefs.setInt(storeKey, value); + } + + Future setList(String key, List value, + {bool isWithUser = true}) async { + String storeKey = key; + if (isWithUser) { + storeKey = '${AuthStore.to.userInfo.value.userId}_$key'; + } + return await _prefs.setStringList(storeKey, value); + } + + String? getString(String key, {bool isWithUser = true}) { + String storeKey = key; + if (isWithUser) { + storeKey = '${AuthStore.to.userInfo.value.userId}_$key'; + } + return _prefs.getString(storeKey); + } + + int? getInt(String key, {bool isWithUser = true}) { + String storeKey = key; + if (isWithUser) { + storeKey = '${AuthStore.to.userInfo.value.userId}_$key'; + } + return _prefs.getInt(storeKey); + } + + bool? getBool(String key, {bool isWithUser = true}) { + String storeKey = key; + if (isWithUser) { + storeKey = '${AuthStore.to.userInfo.value.userId}_$key'; + } + return _prefs.getBool(storeKey) ?? false; + } + + List getList(String key, {bool isWithUser = true}) { + String storeKey = key; + if (isWithUser) { + storeKey = '${AuthStore.to.userInfo.value.userId}_$key'; + } + return _prefs.getStringList(storeKey) ?? []; + } + + Future remove(String key, {bool isWithUser = true}) async { + String storeKey = key; + if (isWithUser) { + storeKey = '${AuthStore.to.userInfo.value.userId}_$key'; + } + return await _prefs.remove(storeKey); + } + + //Warning. if you use this method, all users data will be deleted + Future clear() async { + return await _prefs.clear(); + } +} diff --git a/lib/store/auth.store.dart b/lib/store/auth.store.dart new file mode 100644 index 0000000..23fd73b --- /dev/null +++ b/lib/store/auth.store.dart @@ -0,0 +1,167 @@ +import 'dart:convert'; + +import 'package:dio/dio.dart' as Dio; +import 'package:get/get.dart'; +import 'package:sk_base_mobile/apis/api.dart' as Api; +import 'package:sk_base_mobile/util/logger_util.dart'; +import 'package:sk_base_mobile/widgets/tap_to_dismiss_keyboard.dart'; +import 'package:sk_base_mobile/config.dart'; +import 'package:sk_base_mobile/models/auth.dart'; +import 'package:sk_base_mobile/models/user_info.model.dart'; +import 'package:sk_base_mobile/services/service.dart'; +import '../constants/constants.dart'; +import '../util/util.dart'; + +class AuthStore extends GetxController { + static AuthStore get to => Get.find(); + final userInfo = UserInfoModel().obs; + + Future init() async { + try { + String? preUserInfo = + StorageService.to.getString(CacheKeys.userInfo, isWithUser: false); + String? token = + StorageService.to.getString(CacheKeys.token, isWithUser: false); + + // if (token != null) { + // final response = await Api.isValidToken(token); + // if (response.data != null) { + // // Token有效无需登录 + // if (response.data['data'] == true) { + // } else { + // LoggerUtil().info('[Store-Auth] Token invalid, need to login.'); + // await StorageService.to.remove(CacheKeys.token, isWithUser: false); + // } + // if (preUserInfo != null) { + // userInfo(UserInfoModel.fromJson(jsonDecode(preUserInfo))); + // LoggerUtil().info('[Store-Auth] userId: ${userInfo.value.userId}'); + // } + // } + // } + } catch (e) { + LoggerUtil().info( + '[Store-Auth]Init failed, please try again.${e}', + ); + } + return this; + } + + Future deleteAccount() async { + await LoadingUtil.show(status: 'Deleting...'); + try { + final response = await Api.deleteAccount(); + if (response.data != null) { + await SnackBarUtil().success('Delete account succeed.'); + await logout(); + } + } catch (e) { + await SnackBarUtil().error('Delete account faield. Please try again.'); + } finally { + await LoadingUtil.dismiss(); + ; + } + } + + Future logout({bool force = false}) async { + await LoadingUtil.show(status: 'Logout...'); + await StorageService.to.remove(CacheKeys.token, isWithUser: false); + await StorageService.to.remove(CacheKeys.userInfo, isWithUser: false); + try { + final response = await Api.logout(); + if (response.data != null) { + LoggerUtil().info('[Store-Auth] Logout succeed.'); + if (Get.context != null) Get.offAllNamed(RouteConfig.login); + } + } catch (e) { + } finally { + LoadingUtil.dismiss(); + } + } + + Future login(LoginEnum type, {String? identityToken}) async { + Dio.Response response; + if (type == LoginEnum.fastLogin && + StorageService.to.getString(CacheKeys.deviceUUID, isWithUser: false) == + null) { + SnackBarUtil().error('Need DeviceUUID. Please restart app.'); + return; + } + + LoadingUtil.show(status: 'Login...'); + // Hide keyboard + TapToDismissKeyboard.dismissOf(context: Get.context!); + try { + response = await Api.login( + '4', + type == LoginEnum.fastLogin + ? (StorageService.to + .getString(CacheKeys.deviceUUID, isWithUser: false)) + : identityToken); + + if (response.data != null) { + final auth = Auth.fromJson(response.data['data']); + if (auth.token != null) { + await StorageService.to + .setString(CacheKeys.token, auth.token!, isWithUser: false); + } + if (auth.userInfo != null) { + userInfo(auth.userInfo!); + await StorageService.to.setString( + CacheKeys.userInfo, jsonEncode(auth.userInfo), + isWithUser: false); + LoggerUtil().info('[Store-Auth] Login succeed.'); + } + Get.offNamed(RouteConfig.home); + getCommonInfo(); + } + } catch (e) { + SnackBarUtil().error('${e}'); + } finally { + LoadingUtil.dismiss(); + } + } + + Future updateUserInfoState(UserInfoModel newInfo) async { + userInfo(newInfo); + await StorageService.to + .setString(CacheKeys.userInfo, jsonEncode(newInfo), isWithUser: false); + } + + Future getUserInfo() async { + await LoadingUtil.show(status: 'Loading...'); + try { + final response = await Api.getUserInfo(userInfo.value.userId!); + if (response.data != null) { + UserInfoModel userInfo = UserInfoModel.fromJson(response.data['data']); + await updateUserInfoState(userInfo); + } + } catch (e) { + SnackBarUtil().error('$e'); + } finally { + LoadingUtil.dismiss(); + } + } + + Future saveUserInfo(Map data) async { + LoadingUtil.show(status: 'Saving...'); + try { + final res = await Api.saveUserInfo(data); + if (res.data != null) { + await getUserInfo(); + SnackBarUtil().success('Save successfully.'); + } + } catch (e) { + SnackBarUtil().error('$e'); + } finally { + LoadingUtil.dismiss(); + } + } + + Future getCommonInfo() async { + await AppInfoService.to.getAppConfig(); + await Future.wait([ + /// 依赖业务信息 + // Get.putAsync(() => BlockStore().init()), + ]); + } +} diff --git a/lib/store/store.dart b/lib/store/store.dart new file mode 100644 index 0000000..7bc4533 --- /dev/null +++ b/lib/store/store.dart @@ -0,0 +1,3 @@ +library store; + +export 'auth.store.dart'; diff --git a/lib/util/common.util.dart b/lib/util/common.util.dart new file mode 100644 index 0000000..6c6bc1d --- /dev/null +++ b/lib/util/common.util.dart @@ -0,0 +1,29 @@ +import 'dart:math'; +import 'package:crypto/crypto.dart'; +import 'dart:convert'; + +class CommonUtil { + static String generateMd5(String input) { + List bytes = utf8.encode(input); // 将字符串转换为字节码 + Digest md5Hash = md5.convert(bytes); // 对字节码进行MD5加密 + String encryptedString = md5Hash.toString(); // 获取加密后的字符串 + return encryptedString; + } + + static String generateTicketNumber() { + Random random = Random(); + + int randomTwoDigitNumber = random.nextInt(99); + String twoDigitNumber = randomTwoDigitNumber.toString().padLeft(2, '0'); + + // 格式化数字串 + String formattedNumber = + '${random.nextInt(9999999).toString().padLeft(7, '0')}${random.nextInt(9999999).toString().padLeft(7, '0')}-$twoDigitNumber'; + + return formattedNumber; + } + + static String firstUppercase(String text) { + return '${text[0].toUpperCase()}${text.substring(1)}'; + } +} diff --git a/lib/util/convert.dart b/lib/util/convert.dart new file mode 100644 index 0000000..2f8075c --- /dev/null +++ b/lib/util/convert.dart @@ -0,0 +1,71 @@ +Map toMap(dynamic value, {reserveNull = false}) { + Map map = Map(); + + if (value == null) return map; + + if (value is Map) { + map = Map.from(value); + } + + if (value is List) { + map = Map.from(value.asMap()); + } + + if (!reserveNull) { + map.removeWhere((key, value) => value == null); + } + + return map; +} + +/// convert snapshot value to a list +List toList(dynamic value, {reserveNull = false}) { + List list = []; + + if (value == null) return list; + + if (value is List) { + list = List.from(value); + } + + if (value is Map) { + list = Map.from(value).values.toList(); + } + + if (reserveNull) { + return list; + } + + return list.where((element) => element != null).toList(); +} + +/// Convert any data into double or null if it can not be parsed +double? asDouble(dynamic source) { + if (source == null) { + return null; + } + return double.tryParse(source.toString()); +} + +/// Convert any data into int or null if it can not be parsed +int? asInt(dynamic source, {int? radix}) { + if (source == null) { + return null; + } + return int.tryParse(source.toString(), radix: radix); +} + +bool asBool(dynamic source) { + if (source == null) { + return false; + } + + if (source is num) { + return source > 0; + } + if (source is bool) { + return source; + } + + return false; +} diff --git a/lib/util/debouncer.dart b/lib/util/debouncer.dart new file mode 100644 index 0000000..bfde83e --- /dev/null +++ b/lib/util/debouncer.dart @@ -0,0 +1,39 @@ +/* import 'package:flutter/foundation.dart'; +import 'dart:async'; + +class Debouncer { + + final int milliseconds; + VoidCallback action; + Timer _timer; + + Debouncer({ milliseconds }); +/* */ + run(VoidCallback action) { + if (_timer != null) { + _timer.cancel(); + } + _timer = Timer(Duration(milliseconds: milliseconds), action); + } +} + */ +import 'dart:async'; + +/// 函数防抖 +/// +/// [func]: 要执行的方法 +/// [delay]: 要迟延的时长 +Function(T) debouncer(Function(T text)? func, {int? delayTime}) { + Duration delay = Duration(milliseconds: delayTime ?? 1500); + + Timer? timer; + Function(T) target = (T value) { + if (timer?.isActive ?? false) { + timer?.cancel(); + } + timer = Timer(delay, () { + if (func != null) func.call(value); + }); + }; + return target; +} diff --git a/lib/util/loading_util.dart b/lib/util/loading_util.dart new file mode 100644 index 0000000..eb1f792 --- /dev/null +++ b/lib/util/loading_util.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +/// Loading工具 +class LoadingUtil { + LoadingUtil() {} + init() {} + + static Future show({String? status}) async { + return showLoading(status: status ?? 'Loading...'); + } + + static Future dismiss() async { + return hideLoading(); + } + + static showLoading({String? status}) { + Get.dialog( + GestureDetector( + child: Container( + color: Colors.black54, + child: const Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + ), + onTap: () { + // 点击是否退出模态框 + Get.back(); + }, + ), + barrierDismissible: false, + ); + } + + static hideLoading() { + Get.back(); + } +} diff --git a/lib/util/logger_util.dart b/lib/util/logger_util.dart new file mode 100644 index 0000000..04420f9 --- /dev/null +++ b/lib/util/logger_util.dart @@ -0,0 +1,12 @@ +import 'package:get/get.dart'; +import 'package:sk_base_mobile/config.dart'; + +class LoggerUtil { + void error(dynamic msg) { + if (GloablConfig.DEBUG) printError(info: '$msg'); + } + + void info(dynamic msg) { + if (GloablConfig.DEBUG) printInfo(info: '$msg'); + } +} diff --git a/lib/util/media_util.dart b/lib/util/media_util.dart new file mode 100644 index 0000000..fd9baf1 --- /dev/null +++ b/lib/util/media_util.dart @@ -0,0 +1,191 @@ +import 'dart:io'; +import 'package:dio/dio.dart' as Dio; +import 'package:sk_base_mobile/apis/api.dart' as Api; +import 'package:image_picker/image_picker.dart'; +import 'package:sk_base_mobile/services/service.dart'; + +class MediaUtil { + //拍照 + Future getImageFromCamera({double? maxWidth}) async { + XFile? pickedFile; + try { + if (AppInfoService.to.isCameraing.value) { + return null; + } + AppInfoService.to.isCameraing.value = true; + pickedFile = await ImagePicker() + .pickImage(source: ImageSource.camera, maxWidth: maxWidth ?? 400); + AppInfoService.to.isCameraing.value = false; + } catch (e) { + AppInfoService.to.isCameraing.value = false; + } + return pickedFile; + } + + //相册选择 单张 + Future getImageFromGallery() async { + if (AppInfoService.to.isCameraing.value) { + return null; + } + AppInfoService.to.isCameraing.value = true; + XFile? pickedFile = await ImagePicker().pickImage( + source: ImageSource.gallery, + ); + AppInfoService.to.isCameraing.value = false; + return pickedFile; + } + + Future uploadImg(File imgfile) async { + Dio.Response response = await Api.uploadImg(imgfile); + if (response.data != null && response.data['data']['filename'] != null) { + return response.data["data"]["filename"]; + } + return ''; + } + + // // 上传一张照片 + // Future uploadMediaWithProgress( + // File imgfile, Function onProgress) async { + // Response response = await Api.uploadMediaWithProgress(imgfile, onProgress); + // if (response.data != null && response.data['code'] == 200) { + // return response.data['data']['url']; + // } else { + // throw Exception('上传照片失败'); + // } + // } + + // // 上传多张照片 + // Future> uploadMultiImgs(List imgfiles) async { + // Response response = await Api.uploadMultiImgs(imgfiles); + // List urlList = []; + // if (response.data != null && response.data['code'] == 200) { + // String url = response.data['data']['url']; + // urlList = url.split(','); + // return urlList; + // } else { + // throw Exception('上传照片失败'); + // } + // } + + // // 保存到相册 + // Future saveImageToPhotoLib({required String imgUrl, String? filename}) async { + // // ?? "http://qiniu-app.hua10.com/20190815155000_256512.png" + // var response = await Dio() + // .get(imgUrl, options: Options(responseType: ResponseType.bytes)); + // final result = await ImageGallerySaver.saveImage( + // Uint8List.fromList(response.data), + // quality: 60); + // return result; + // } + + // ///选取视频 + // Future getVideoFromGallery() async { + // if (AppInfoModel().isCameraing) { + // return null; + // } + // XFile? pickedFile = + // await ImagePicker().pickVideo(source: ImageSource.gallery); + // if (pickedFile != null) { + // var path = pickedFile.path; + // if (Platform.isAndroid) { + // var newPath = path.replaceAll('.jpg', '.mp4'); + // File(path).renameSync(newPath); + // return XFile(newPath); + // } + // } + // return pickedFile; + // } + + // /*拍摄视频*/ + // Future takeVideoFromCamera() async { + // var image = await ImagePicker().getVideo(source: ImageSource.camera); + // print('拍摄视频:' + image.toString()); + // } + + // /// 生成视频缩略图 + // Future generateLogoUrl(String videoUrl) async { + // File file = await generateLogoFile(videoUrl: videoUrl); + // return await MediaUtil().uploadImg(file); + // } + + // /// 生成视频缩略图 + // Future generateLogoFile({String? videoUrl, String? videoPath}) async { + // Directory fileDic = await getApplicationDocumentsDirectory(); + + // String? path = await VideoThumbnail.thumbnailFile( + // video: videoUrl ?? videoPath!, + // imageFormat: ImageFormat.JPEG, + // thumbnailPath: fileDic.path, + // // maxWidth: 200, + // // 64, // specify the height of the thumbnail, let the width auto-scaled to keep the source aspect ratio + // quality: 100, + // ); + // return File(path!); + // } + + // /// 获取文件类型Video/audio/image + // MediaTypeEnum getMediaTypeBySuffix(String? url) { + // if (url == null || url == '') { + // return MediaTypeEnum.IMAGE; + // } + // String suffix = url.split('.')[url.split('.').length - 1].toLowerCase(); + // if (videoSuffix.contains(suffix)) { + // return MediaTypeEnum.VIDEO; + // } else if (audioSuffix.contains(suffix)) { + // return MediaTypeEnum.AUDIO; + // } + // return MediaTypeEnum.IMAGE; + // } + + // List videoSuffix = [ + // 'avi', + // 'wmv', + // 'mpg', + // 'mpeg', + // 'mov', + // 'rm', + // 'ram', + // 'swf', + // 'flv', + // 'mp4' + // ]; + // List audioSuffix = [ + // 'aac', + // 'mp3', + // 'cda', + // 'wav', + // 'wma', + // 'ra', + // 'rma', + // 'ape', + // 'asf', + // 'mid', + // 'midi', + // 'rmi', + // 'xmi', + // 'ogg', + // 'ape', + // 'aiff', + // 'au' + // ]; + // List imageSuffix = [ + // 'webp', + // 'bmp', + // 'pcx', + // 'tif', + // 'gif', + // 'jpeg', + // 'tga', + // 'exif', + // 'fpx', + // 'svg', + // 'psd', + // 'cdr', + // 'png', + // 'ogg', + // 'ape', + // 'aiff', + // 'au', + // 'jpg' + // ]; +} diff --git a/lib/util/photo_picker_util.dart b/lib/util/photo_picker_util.dart new file mode 100644 index 0000000..02c45b5 --- /dev/null +++ b/lib/util/photo_picker_util.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:get/get.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:sk_base_mobile/util/media_util.dart'; +import 'package:sk_base_mobile/app_theme.dart'; + +class PhotoPickerUtil { + showPicker({Function? callback}) async { + return showCupertinoModalPopup( + context: Get.context!, + builder: (BuildContext ctx) { + return CupertinoActionSheet( + title: const Text('Change avatar'), + cancelButton: CupertinoActionSheetAction( + onPressed: () { + Get.back(); + }, + child: const Text( + 'Cancel', + style: TextStyle(color: Color(0xffcdcdcd)), + )), + actions: ['Photography', 'Album'] + .map((item) => CupertinoActionSheetAction( + onPressed: () async { + Get.back(); + XFile? pickedFile = item == 'Photography' + ? await MediaUtil().getImageFromCamera() + : await MediaUtil().getImageFromGallery(); + if (pickedFile != null) { + if (callback != null) { + callback(pickedFile); + } + } + }, + child: Text( + item, + style: const TextStyle(color: AppTheme.primaryColor), + ))) + .toList(), + ); + }); + } +} diff --git a/lib/util/screen_adaper_util.dart b/lib/util/screen_adaper_util.dart new file mode 100644 index 0000000..e93f534 --- /dev/null +++ b/lib/util/screen_adaper_util.dart @@ -0,0 +1,50 @@ +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; + +/// 屏幕适配类 +class ScreenAdaper { + /// 获取 计算后的字体 + static double sp(double value) { + return ScreenUtil().setSp(value); + } + + /// 获取 计算后的高度 + static double height(double value) { + return isLandspace() + ? ScreenUtil().setWidth(value) + : ScreenUtil().setHeight(value); + } + + /// 获取 计算后的宽度 + static double width(double value) { + return isLandspace() + ? ScreenUtil().setHeight(value) + : ScreenUtil().setWidth(value); + } + + /// 获取 计算后的屏幕高度 + static double screenHeight({notAdapt = false}) { + return (isLandspace() && !notAdapt) + ? ScreenUtil().screenWidth + : ScreenUtil().screenHeight; + } + + /// 获取 计算后的屏幕宽度 + static double screenWidth() { + return isLandspace() ? ScreenUtil().screenHeight : ScreenUtil().screenWidth; + } + + /// 获取 计算后的radius + static radius(double value) { + return ScreenUtil().radius(value); + } + + /// Text 尾部整个单词全部变成省略号的问题 + static overflowByChar(String? text) { + return '${text ?? ''}'.replaceAll('', '\u200B'); + } + + static isLandspace() { + return Get.width > Get.height; + } +} diff --git a/lib/util/snack_bar.util.dart b/lib/util/snack_bar.util.dart new file mode 100644 index 0000000..649188d --- /dev/null +++ b/lib/util/snack_bar.util.dart @@ -0,0 +1,94 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:sk_base_mobile/app_theme.dart'; + +// SnackBar 工具 +class SnackBarUtil { + checkIsSnackBarInit() { + return Get.overlayContext != null; + } + + Future error(String? title, {dynamic error}) async { + if (checkIsSnackBarInit()) { + if (error is Exception) { + title = error.toString(); + } + + if (error is DioException) { + title = error.message; + if (error.response?.data is Map) { + title = error.response?.data['message'] ?? title; + } + } + if (Get.isSnackbarOpen) { + await Get.closeCurrentSnackbar(); + } + Get.rawSnackbar( + message: title, + snackPosition: SnackPosition.TOP, + backgroundColor: AppTheme.snackbarErrorBackgroudColor, + borderRadius: 15, + margin: EdgeInsets.symmetric(horizontal: 10, vertical: 0), + overlayColor: Colors.white, + duration: Duration(seconds: 3), + forwardAnimationCurve: Curves.fastLinearToSlowEaseIn, + reverseAnimationCurve: Curves.linearToEaseOut); + } + } + + Future success(String title, {String? message}) async { + if (checkIsSnackBarInit()) { + if (Get.isSnackbarOpen) { + await Get.closeCurrentSnackbar(); + } + Get.rawSnackbar( + message: title, + snackPosition: SnackPosition.TOP, + backgroundColor: AppTheme.snackbarSuccessBackgroudColor, + borderRadius: 15, + margin: EdgeInsets.symmetric(horizontal: 10, vertical: 0), + overlayColor: Colors.white, + duration: Duration(seconds: 2), + dismissDirection: DismissDirection.horizontal, + forwardAnimationCurve: Curves.fastLinearToSlowEaseIn, + reverseAnimationCurve: Curves.linearToEaseOut); + } + } + + Future info(String title, {String? message}) async { + if (checkIsSnackBarInit()) { + if (Get.isSnackbarOpen) { + await Get.closeCurrentSnackbar(); + } + Get.rawSnackbar( + message: title, + snackPosition: SnackPosition.TOP, + borderRadius: 15, + margin: EdgeInsets.symmetric(horizontal: 10, vertical: 0), + duration: Duration(seconds: 2), + dismissDirection: DismissDirection.horizontal, + forwardAnimationCurve: Curves.fastLinearToSlowEaseIn, + reverseAnimationCurve: Curves.linearToEaseOut); + } + } + + Future warning(String title, {String? message}) async { + if (checkIsSnackBarInit()) { + if (Get.isSnackbarOpen) { + await Get.closeCurrentSnackbar(); + } + Get.rawSnackbar( + message: title, + snackPosition: SnackPosition.TOP, + backgroundColor: AppTheme.snackbarWarningBackgroudColor, + borderRadius: 15, + margin: EdgeInsets.symmetric(horizontal: 10, vertical: 0), + overlayColor: Colors.white, + duration: Duration(seconds: 2), + dismissDirection: DismissDirection.horizontal, + forwardAnimationCurve: Curves.fastLinearToSlowEaseIn, + reverseAnimationCurve: Curves.linearToEaseOut); + } + } +} diff --git a/lib/util/throttler.dart b/lib/util/throttler.dart new file mode 100644 index 0000000..4b9bef0 --- /dev/null +++ b/lib/util/throttler.dart @@ -0,0 +1,25 @@ +// throttle.dart + +import 'dart:async'; + +/// 函数节流 +/// +/// [func]: 要执行的方法 +Function throttler( + Future Function(String text) func, +) { + + if (func == null) { + return func; + } + bool enable = true; + Function target = (String value) { + if (enable == true) { + enable = false; + func(value).then((_) { + enable = true; + }); + } + }; + return target; +} diff --git a/lib/util/util.dart b/lib/util/util.dart new file mode 100644 index 0000000..003df36 --- /dev/null +++ b/lib/util/util.dart @@ -0,0 +1,8 @@ +library store; + +export 'snack_bar.util.dart'; +export 'loading_util.dart'; +export 'media_util.dart'; +export 'photo_picker_util.dart'; +export 'screen_adaper_util.dart'; +export 'validator_util.dart'; diff --git a/lib/util/validator_util.dart b/lib/util/validator_util.dart new file mode 100644 index 0000000..7d81985 --- /dev/null +++ b/lib/util/validator_util.dart @@ -0,0 +1,11 @@ +class ValidatorUtil { + String? emailValidator(value) { + if (value == null || value == '') { + return 'Email is required'; + } + final String regexEmail = + "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*\$"; + if (value == null || value.isEmpty) return null; + return new RegExp(regexEmail).hasMatch(value) ? null : 'Email format error'; + } +} diff --git a/lib/widgets/empty.dart b/lib/widgets/empty.dart new file mode 100644 index 0000000..ade11bd --- /dev/null +++ b/lib/widgets/empty.dart @@ -0,0 +1,25 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:sk_base_mobile/util/screen_adaper_util.dart'; + +class Empty extends StatelessWidget { + String? text; + Empty({super.key, this.text}); + + @override + Widget build(BuildContext context) { + return Center( + child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + Center( + child: Image( + height: ScreenAdaper.height(130), + image: AssetImage('assets/images/empty_icon.png'))), + Text( + text ?? '', + textAlign: TextAlign.center, + style: TextStyle(fontSize: ScreenAdaper.sp(18)), + ), + ]), + ); + } +} diff --git a/lib/widgets/fade_in_cache_image.dart b/lib/widgets/fade_in_cache_image.dart new file mode 100644 index 0000000..2a6b1cf --- /dev/null +++ b/lib/widgets/fade_in_cache_image.dart @@ -0,0 +1,77 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:sk_base_mobile/app_theme.dart'; + +class FadeInCacheImage extends StatefulWidget { + final double? width; + final double? height; + final String? url; + final BoxFit? fit; + bool compress; + bool canFullscreen; + FadeInCacheImage( + {Key? key, + this.width, + this.height, + this.url, + this.fit = BoxFit.cover, + this.compress = false, + this.canFullscreen = false}) + : super(key: key); + + @override + _FadeInCacheImageState createState() => _FadeInCacheImageState(); +} + +class _FadeInCacheImageState extends State { + late BuildContext theContext; + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + theContext = context; + + if ((widget.url == null || widget.url == '' || widget.url == 'null')) { + return Image( + width: widget.width, + height: widget.height, + fit: widget.fit, + image: AssetImage( + 'assets/images/deer_detail_banner1.jpg', + )); + } + + return buildImg(widget.url); + ; + } + + // Future getImg() { + // return MediaUtil().generateLogoUrl(widget.url); + // } + + Widget buildImg(String? url) { + return CachedNetworkImage( + alignment: Alignment.center, + imageUrl: url ?? '', + width: widget.width, + height: widget.height, + fit: widget.fit, + placeholder: (context, url) => Container( + decoration: BoxDecoration(color: AppTheme.grey), + child: CupertinoActivityIndicator(), + ), + errorWidget: (context, error, stackTrace) => Image( + image: AssetImage( + 'assets/images/deer_detail_banner1.jpg', + )), + ); + } +} diff --git a/lib/widgets/my_avatar.dart b/lib/widgets/my_avatar.dart new file mode 100644 index 0000000..96ac159 --- /dev/null +++ b/lib/widgets/my_avatar.dart @@ -0,0 +1,102 @@ +import 'dart:io'; +import 'package:sk_base_mobile/apis/api.dart' as Api; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:sk_base_mobile/store/auth.store.dart'; +import 'package:sk_base_mobile/util/media_util.dart'; +import 'package:sk_base_mobile/util/photo_picker_util.dart'; +import 'package:sk_base_mobile/util/loading_util.dart'; +import 'package:sk_base_mobile/util/screen_adaper_util.dart'; +import 'package:sk_base_mobile/util/snack_bar.util.dart'; +import 'package:sk_base_mobile/app_theme.dart'; + +import '../util/util.dart'; + +class MyAvatarWidget extends StatelessWidget { + final _controller = Get.put(MyAvatarController()); + MyAvatarWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Obx(() => Container( + decoration: BoxDecoration( + image: + DecorationImage(fit: BoxFit.cover, image: _buildImage()), + border: Border.all( + color: AppTheme.white, width: ScreenAdaper.sp(2)), + borderRadius: BorderRadius.circular(50)), + height: ScreenAdaper.width(90), + width: ScreenAdaper.width(90), + child: const SizedBox(), + )), + Positioned( + bottom: 0, + right: 0, + child: InkWell( + onTap: () { + _controller.photoPicker(); + }, + child: Image( + height: ScreenAdaper.width(40), + image: const AssetImage('assets/images/photo_icon.png'), + ))) + ], + ); + } + + dynamic _buildImage() { + return _controller.uploadImgFilePath.value.isNotEmpty + ? FileImage(File(_controller.uploadImgFilePath.value)) + : NetworkImage( + AuthStore.to.userInfo.value.avatarThumbUrl ?? '', + ); + } + // Widget getShowImg() { + // // 1.选择的内存照片 + // if (uploadImg != null) { + // return Image(fit: BoxFit.cover, image: FileImage(uploadImg!)); + // } + // // 2.显示回显的照片url地址 + // if (createDto['content'] != null) { + // return FadeInCacheImage( + // url: createDto['content'], + // height: 100, + // width: 100, + // ); + // } + + // // 3.添加图 + // return Image( + // height: 100, + // width: 100, + // fit: BoxFit.cover, + // image: AssetImage('assets/images/common/icon_camera.png')); + // } +} + +class MyAvatarController extends GetxController { + final uploadImgFilePath = ''.obs; + Future photoPicker() async { + await PhotoPickerUtil().showPicker(callback: (XFile pickedFile) async { + await LoadingUtil.show(status: 'Uploading...'); + try { + String? filename = await MediaUtil().uploadImg(File(pickedFile.path)); + if (filename.isNotEmpty) { + final res = await Api.updateAvatar(filename); + if (res.data != null) { + SnackBarUtil().success('Update avatar successfully'); + } + } + uploadImgFilePath(pickedFile.path); + Get.back(); + } catch (e) { + SnackBarUtil().error('Update avatar failed.'); + } finally { + await LoadingUtil.dismiss(); + } + }); + } +} diff --git a/lib/widgets/refresh-footer.dart b/lib/widgets/refresh-footer.dart new file mode 100644 index 0000000..85d8781 --- /dev/null +++ b/lib/widgets/refresh-footer.dart @@ -0,0 +1,57 @@ +import 'package:flutter/cupertino.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:sk_base_mobile/util/screen_adaper_util.dart'; + +class RefreshFooter extends StatefulWidget { + const RefreshFooter({Key? key}) : super(key: key); + + @override + State createState() => _RefreshFooterState(); +} + +class _RefreshFooterState extends State + with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return buildBody(); + } + + Widget buildBody() { + TextStyle style = TextStyle(fontSize: ScreenAdaper.sp(18)); + return CustomFooter( + builder: (BuildContext context, LoadStatus? status) { + Widget body; + if (status == LoadStatus.idle) { + body = const Text("Pull up to get latest messages"); + } else if (status == LoadStatus.loading) { + body = const SizedBox(child: const CupertinoActivityIndicator()); + } else if (status == LoadStatus.failed) { + body = Text( + "Load failed, please try again", + style: style, + ); + } else if (status == LoadStatus.canLoading) { + body = const CupertinoActivityIndicator( + animating: false, + ); + } else { + body = const SizedBox(); + } + return SizedBox( + height: ScreenAdaper.height(20), + child: Center(child: body), + ); + }, + ); + } +} diff --git a/lib/widgets/refresh_header.dart b/lib/widgets/refresh_header.dart new file mode 100644 index 0000000..944d141 --- /dev/null +++ b/lib/widgets/refresh_header.dart @@ -0,0 +1,62 @@ +import 'package:flutter/cupertino.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:sk_base_mobile/util/screen_adaper_util.dart'; + +class RefreshHeader extends RefreshIndicator { + RefreshHeader() + : super( + height: ScreenAdaper.height(100), + refreshStyle: RefreshStyle.Follow); + @override + State createState() { + // TODO: implement createState + return RefreshHeaderState(); + } +} + +class RefreshHeaderState extends RefreshIndicatorState + with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void onModeChange(RefreshStatus? mode) { + super.onModeChange(mode); + } + + @override + Future endRefresh() async {} + + @override + void resetValue() { + super.resetValue(); + } + + @override + Widget buildContent(BuildContext context, RefreshStatus mode) { + TextStyle style = TextStyle(fontSize: ScreenAdaper.sp(18)); + Widget body; + if (mode == RefreshStatus.refreshing) { + body = const CupertinoActivityIndicator(); + } else if (mode == RefreshStatus.canRefresh) { + body = const CupertinoActivityIndicator(animating: false); + } else if (mode == RefreshStatus.completed) { + body = const SizedBox(); + } else if (mode == RefreshStatus.failed) { + body = Text("No more Data)", style: style); + } else { + body = const CupertinoActivityIndicator(); + } + return SizedBox( + height: ScreenAdaper.height(40), + child: Center(child: body), + ); + } + + @override + void dispose() { + super.dispose(); + } +} diff --git a/lib/widgets/tap_to_dismiss_keyboard.dart b/lib/widgets/tap_to_dismiss_keyboard.dart new file mode 100644 index 0000000..5e993ea --- /dev/null +++ b/lib/widgets/tap_to_dismiss_keyboard.dart @@ -0,0 +1,22 @@ +import 'package:flutter/cupertino.dart'; + +class TapToDismissKeyboard extends StatelessWidget { + final Widget? child; + late BuildContext context; + + TapToDismissKeyboard({this.child, required context}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + TapToDismissKeyboard.dismissOf(context: context); + }, + child: child, + ); + } + + static dismissOf({required BuildContext context}) { + FocusScope.of(context).requestFocus(FocusNode()); + } +} diff --git a/lib/widgets/want_keep_alive.dart b/lib/widgets/want_keep_alive.dart new file mode 100644 index 0000000..fcb8778 --- /dev/null +++ b/lib/widgets/want_keep_alive.dart @@ -0,0 +1,24 @@ +import 'package:flutter/cupertino.dart'; + +class WantKeepAlive extends StatefulWidget { + final Widget child; + + WantKeepAlive({required this.child}); + + @override + State createState() { + return WantKeepAliveState(); + } +} + +class WantKeepAliveState extends State + with AutomaticKeepAliveClientMixin { + @override + Widget build(BuildContext context) { + super.build(context); + return widget.child; + } + + @override + bool get wantKeepAlive => true; +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..91c1cab --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,866 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "8bf17a8ff6ea17499e40a2d2542c2f481cd7615760c6d34065cb22bfd22e6880" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + archive: + dependency: transitive + description: + name: archive + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + url: "https://pub.dev" + source: hosted + version: "3.4.10" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + url: "https://pub.dev" + source: hosted + version: "0.4.1" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: "direct main" + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + url: "https://pub.dev" + source: hosted + version: "0.3.3+8" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.dev" + source: hosted + version: "1.0.6" + date_format: + dependency: "direct main" + description: + name: date_format + sha256: "8e5154ca363411847220c8cbc43afcf69c08e8debe40ba09d57710c25711760c" + url: "https://pub.dev" + source: hosted + version: "2.0.7" + dio: + dependency: "direct main" + description: + name: dio + sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8" + url: "https://pub.dev" + source: hosted + version: "5.4.1" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + faker: + dependency: "direct main" + description: + name: faker + sha256: "746e59f91d8b06a389e74cf76e909a05ed69c12691768e2f93557fdf29200fd0" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + ffi: + dependency: transitive + description: + name: ffi + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" + url: "https://pub.dev" + source: hosted + version: "0.9.2+1" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + url: "https://pub.dev" + source: hosted + version: "0.13.1" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + flutter_native_splash: + dependency: "direct dev" + description: + name: flutter_native_splash + sha256: "45e2c0986d749c070509e03d6c7ad6c8bd1f7b1dad7d11dd8750a5e4fe3e2c0b" + url: "https://pub.dev" + source: hosted + version: "2.3.11" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + url: "https://pub.dev" + source: hosted + version: "2.0.17" + flutter_screenutil: + dependency: "direct main" + description: + name: flutter_screenutil + sha256: "8cf100b8e4973dc570b6415a2090b0bfaa8756ad333db46939efc3e774ee100d" + url: "https://pub.dev" + source: hosted + version: "5.9.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + get: + dependency: "direct main" + description: + name: get + sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e + url: "https://pub.dev" + source: hosted + version: "4.6.6" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + http: + dependency: transitive + description: + name: http + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba + url: "https://pub.dev" + source: hosted + version: "1.2.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" + url: "https://pub.dev" + source: hosted + version: "4.1.7" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "26222b01a0c9a2c8fe02fc90b8208bd3325da5ed1f4a2acabf75939031ac0bdd" + url: "https://pub.dev" + source: hosted + version: "1.0.7" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1" + url: "https://pub.dev" + source: hosted + version: "0.8.9+3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: e2423c53a68b579a7c37a1eda967b8ae536c3d98518e5db95ca1fe5719a730a3 + url: "https://pub.dev" + source: hosted + version: "3.0.2" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "917a5cadd67d052554cfb258595e54217de53fac5b52939426e26319a02e6297" + url: "https://pub.dev" + source: hosted + version: "0.8.9+2" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: fa4e815e6fcada50e35718727d83ba1c92f1edf95c0b4436554cec301b56233b + url: "https://pub.dev" + source: hosted + version: "2.9.3" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + intl: + dependency: transitive + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + loading_animation_widget: + dependency: "direct main" + description: + name: loading_animation_widget + sha256: ee3659035528d19145d50cf0107632bf647e7306c88b6a32f35f3bed63f6d728 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" + source: hosted + version: "0.12.16" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + meta: + dependency: transitive + description: + name: meta + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + url: "https://pub.dev" + source: hosted + version: "1.10.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + package_info: + dependency: "direct main" + description: + name: package_info + sha256: "6c07d9d82c69e16afeeeeb6866fe43985a20b3b50df243091bfc4a4ad2b03b75" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "74e962b7fad7ff75959161bb2c0ad8fe7f2568ee82621c9c2660b751146bfe44" + url: "https://pub.dev" + source: hosted + version: "11.3.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474" + url: "https://pub.dev" + source: hosted + version: "12.0.5" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: bdafc6db74253abb63907f4e357302e6bb786ab41465e8635f362ee71fd8707b + url: "https://pub.dev" + source: hosted + version: "9.4.0" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d" + url: "https://pub.dev" + source: hosted + version: "0.1.1" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "23dfba8447c076ab5be3dee9ceb66aad345c4a648f0cac292c77b1eb0e800b78" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + url: "https://pub.dev" + source: hosted + version: "3.7.4" + pull_to_refresh: + dependency: "direct main" + description: + name: pull_to_refresh + sha256: bbadd5a931837b57739cf08736bea63167e284e71fb23b218c8c9a6e042aad12 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + url: "https://pub.dev" + source: hosted + version: "2.3.5" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 + url: "https://pub.dev" + source: hosted + version: "2.3.2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" + source: hosted + version: "0.6.1" + timeago: + dependency: "direct main" + description: + name: timeago + sha256: d3204eb4c788214883380253da7f23485320a58c11d145babc82ad16bf4e7764 + url: "https://pub.dev" + source: hosted + version: "3.6.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + uuid: + dependency: transitive + description: + name: uuid + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 + url: "https://pub.dev" + source: hosted + version: "4.3.3" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + url: "https://pub.dev" + source: hosted + version: "0.3.0" + win32: + dependency: transitive + description: + name: win32 + sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + url: "https://pub.dev" + source: hosted + version: "5.2.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.2.6 <4.0.0" + flutter: ">=3.16.6" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..99bf8fe --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,123 @@ +name: sk_base_mobile +description: "山东矿机管理app" +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.devz + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.2.6 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + shared_preferences: ^2.2.2 + dio: ^5.4.1 + faker: ^2.1.0 + image_picker: ^1.0.7 + loading_animation_widget: ^1.2.1 + pull_to_refresh: ^2.0.0 + collection: ^1.18.0 + cached_network_image: ^3.3.1 + get: ^4.6.6 + flutter_screenutil: ^5.9.0 + package_info: ^2.0.2 + timeago: ^3.6.1 + + permission_handler: ^11.3.0 + crypto: ^3.0.3 + date_format: ^2.0.7 + + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # 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: ^2.0.0 + flutter_launcher_icons: ^0.13.1 + flutter_native_splash: ^2.3.11 +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec +flutter_launcher_icons: + android: 'launcher_icon' + ios: true + image_path: 'assets/icons/logo.png' + min_sdk_android: 21 # android min sdk min:16, default 21 +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + assets: + - assets/ + - assets/icons/ + - assets/images/ + fonts: + - family: NotoSans + fonts: + - asset: assets/fonts/NotoSans-Regular.ttf + - asset: assets/fonts/NotoSans-Medium.ttf + weight: 500 + - asset: assets/fonts/NotoSans-SemiBold.ttf + weight: 600 + - asset: assets/fonts/NotoSans-Bold.ttf + weight: 700 + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages